Beispiel #1
0
def main():
    parser = argparse.ArgumentParser()
    logging_common.AddLoggingArguments(parser)
    script_common.AddEnvironmentArguments(parser)
    # TODO(crbug.com/1097306): Remove this once callers switch to --denylist-file.
    parser.add_argument('--blacklist-file', help=argparse.SUPPRESS)
    parser.add_argument('--denylist-file', help='Device denylist JSON file.')
    parser.add_argument('--known-devices-file',
                        action='append',
                        default=[],
                        dest='known_devices_files',
                        help='Path to known device lists.')
    parser.add_argument('--enable-usb-reset',
                        action='store_true',
                        help='Reset USB if necessary.')

    args = parser.parse_args()
    logging_common.InitializeLogging(args)
    script_common.InitializeEnvironment(args)

    denylist = (device_denylist.Denylist(args.denylist_file)
                if args.denylist_file else None)
    # TODO(crbug.com/1097306): Remove this once callers switch to --denylist-file.
    if not denylist and args.blacklist_file:
        denylist = device_denylist.Denylist(args.blacklist_file)

    expected_devices = device_status.GetExpectedDevices(
        args.known_devices_files)
    usb_devices = set(lsusb.get_android_devices())
    devices = [
        device_utils.DeviceUtils(s)
        for s in expected_devices.union(usb_devices)
    ]

    RecoverDevices(devices, denylist, enable_usb_reset=args.enable_usb_reset)
Beispiel #2
0
def ProvisionDevices(args):
    denylist = (device_denylist.Denylist(args.denylist_file)
                if args.denylist_file else None)
    devices = [
        d for d in device_utils.DeviceUtils.HealthyDevices(denylist)
        if not args.emulators or d.adb.is_emulator
    ]
    if args.device:
        devices = [d for d in devices if d == args.device]
    if not devices:
        raise device_errors.DeviceUnreachableError(args.device)
    parallel_devices = device_utils.DeviceUtils.parallel(devices)
    if args.emulators:
        parallel_devices.pMap(SetProperties, args)
    else:
        parallel_devices.pMap(ProvisionDevice, denylist, args)
    if args.auto_reconnect:
        _LaunchHostHeartbeat()
    denylisted_devices = denylist.Read() if denylist else []
    if args.output_device_denylist:
        with open(args.output_device_denylist, 'w') as f:
            json.dump(denylisted_devices, f)
    if all(d in denylisted_devices for d in devices):
        raise device_errors.NoDevicesError
    return 0
Beispiel #3
0
def main(argv):
  """Launches the device monitor.

  Polls the devices for their battery and cpu temperatures and scans the
  denylist file every 60 seconds and dumps the data to DEVICE_FILE.
  """

  parser = argparse.ArgumentParser(description='Launches the device monitor.')
  script_common.AddEnvironmentArguments(parser)
  parser.add_argument('--denylist-file', help='Path to device denylist file.')
  args = parser.parse_args(argv)

  logger = logging.getLogger()
  logger.setLevel(logging.DEBUG)
  handler = logging.handlers.RotatingFileHandler(
      '/tmp/device_monitor.log', maxBytes=10 * 1024 * 1024, backupCount=5)
  fmt = logging.Formatter(
      '%(asctime)s %(levelname)s %(message)s', datefmt='%y%m%d %H:%M:%S')
  handler.setFormatter(fmt)
  logger.addHandler(handler)
  script_common.InitializeEnvironment(args)

  denylist = (device_denylist.Denylist(args.denylist_file)
              if args.denylist_file else None)

  logging.info('Device monitor running with pid %d, adb: %s, denylist: %s',
               os.getpid(), args.adb_path, args.denylist_file)
  while True:
    start = time.time()
    status_dict = get_all_status(denylist)
    with open(DEVICE_FILE, 'wb') as f:
      json.dump(status_dict, f, indent=2, sort_keys=True)
    logging.info('Got status of all devices in %.2fs.', time.time() - start)
    time.sleep(60)
    def __init__(self, args, output_manager, _error_func):
        super(LocalDeviceEnvironment, self).__init__(output_manager)
        self._current_try = 0
        self._denylist = (device_denylist.Denylist(args.denylist_file)
                          if args.denylist_file else None)
        self._device_serials = args.test_devices
        self._devices_lock = threading.Lock()
        self._devices = None
        self._concurrent_adb = args.enable_concurrent_adb
        self._enable_device_cache = args.enable_device_cache
        self._logcat_monitors = []
        self._logcat_output_dir = args.logcat_output_dir
        self._logcat_output_file = args.logcat_output_file
        self._max_tries = 1 + args.num_retries
        self._preferred_abis = None
        self._recover_devices = args.recover_devices
        self._skip_clear_data = args.skip_clear_data
        self._tool_name = args.tool
        self._trace_output = None
        if hasattr(args, 'trace_output'):
            self._trace_output = args.trace_output
        self._trace_all = None
        if hasattr(args, 'trace_all'):
            self._trace_all = args.trace_all

        devil_chromium.Initialize(output_directory=constants.GetOutDirectory(),
                                  adb_path=args.adb_path)

        # Some things such as Forwarder require ADB to be in the environment path,
        # while others like Devil's bundletool.py require Java on the path.
        adb_dir = os.path.dirname(adb_wrapper.AdbWrapper.GetAdbPath())
        if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep):
            os.environ['PATH'] = os.pathsep.join(
                [adb_dir, host_paths.JAVA_PATH, os.environ['PATH']])
    def testDenylistFileDoesNotExist(self):
        with tempfile.NamedTemporaryFile() as denylist_file:
            # Allow the temporary file to be deleted.
            pass

        test_denylist = device_denylist.Denylist(denylist_file.name)
        self.assertEquals({}, test_denylist.Read())
Beispiel #6
0
def GetDevice(finder_options):
    """Return a Platform instance for the device specified by |finder_options|."""
    android_platform_options = finder_options.remote_platform_options
    if not CanDiscoverDevices():
        logging.info(
            'No adb command found. Will not try searching for Android browsers.'
        )
        return None

    if android_platform_options.android_denylist_file:
        denylist = device_denylist.Denylist(
            android_platform_options.android_denylist_file)
    else:
        denylist = None

    if (android_platform_options.device
            and android_platform_options.device in GetDeviceSerials(denylist)):
        return AndroidDevice(android_platform_options.device)

    devices = AndroidDevice.GetAllConnectedDevices(denylist)
    if len(devices) == 0:
        logging.warning('No android devices found.')
        return None
    if len(devices) > 1:
        logging.warning(
            'Multiple devices attached. Please specify one of the following:\n'
            + '\n'.join(['  --device=%s' % d.device_id for d in devices]))
        return None
    return devices[0]
Beispiel #7
0
def FindAllAvailableDevices(options):
    """Returns a list of available devices.
  """
    # Disable Android device discovery when remote testing a CrOS device
    if options.cros_remote:
        return []

    android_platform_options = options.remote_platform_options
    devices = []
    try:
        if CanDiscoverDevices():
            denylist = None
            if android_platform_options.android_denylist_file:
                denylist = device_denylist.Denylist(
                    android_platform_options.android_denylist_file)
            devices = AndroidDevice.GetAllConnectedDevices(denylist)
    finally:
        if not devices and _HasValidAdb():
            try:
                adb_wrapper.AdbWrapper.KillServer()
            except device_errors.NoAdbError as e:
                logging.warning(
                    'adb reported as present, but NoAdbError thrown: %s',
                    str(e))

    return devices
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)
Beispiel #9
0
def main(argv):
    parser = argparse.ArgumentParser(
        usage='Usage: %(prog)s [options] device_port '
        'host_port [device_port_2 host_port_2] ...',
        description=__doc__)
    parser.add_argument('-v',
                        '--verbose',
                        dest='verbose_count',
                        default=0,
                        action='count',
                        help='Verbose level (multiple times for more)')
    parser.add_argument('--device',
                        help='Serial number of device we should use.')
    # TODO(crbug.com/1097306): Remove this once callers have all switched to
    # --denylist-file.
    parser.add_argument('--blacklist-file',
                        dest='denylist_file',
                        help=argparse.SUPPRESS)
    parser.add_argument('--denylist-file', help='Device denylist JSON file.')
    parser.add_argument('--debug',
                        action='store_const',
                        const='Debug',
                        dest='build_type',
                        default='Release',
                        help='DEPRECATED: use --output-directory instead.')
    parser.add_argument('--output-directory',
                        help='Path to the root build directory.')
    parser.add_argument('ports',
                        nargs='+',
                        type=int,
                        help='Port pair to reverse forward.')

    args = parser.parse_args(argv)
    run_tests_helper.SetLogLevel(args.verbose_count)

    if len(args.ports) < 2 or len(args.ports) % 2:
        parser.error('Need even number of port pairs')

    port_pairs = zip(args.ports[::2], args.ports[1::2])

    if args.build_type:
        constants.SetBuildType(args.build_type)
    if args.output_directory:
        constants.SetOutputDirectory(args.output_directory)
    devil_chromium.Initialize(output_directory=constants.GetOutDirectory())

    denylist = (device_denylist.Denylist(args.denylist_file)
                if args.denylist_file else None)
    device = device_utils.DeviceUtils.HealthyDevices(denylist=denylist,
                                                     device_arg=args.device)[0]
    try:
        forwarder.Forwarder.Map(port_pairs, device)
        while True:
            time.sleep(60)
    except KeyboardInterrupt:
        sys.exit(0)
    finally:
        forwarder.Forwarder.UnmapAllDevicePorts(device)
Beispiel #10
0
def main():
    parser = argparse.ArgumentParser()
    logging_common.AddLoggingArguments(parser)
    script_common.AddEnvironmentArguments(parser)
    AddArguments(parser)
    args = parser.parse_args()

    logging_common.InitializeLogging(args)
    script_common.InitializeEnvironment(args)

    denylist = (device_denylist.Denylist(args.denylist_file)
                if args.denylist_file else None)

    expected_devices = GetExpectedDevices(args.known_devices_files)
    usb_devices = set(lsusb.get_android_devices())
    devices = [
        device_utils.DeviceUtils(s)
        for s in expected_devices.union(usb_devices)
    ]

    statuses = DeviceStatus(devices, denylist)

    # Log the state of all devices.
    _LogStatuses(statuses)

    # Update the last devices file(s).
    if args.overwrite_known_devices_files:
        for path in args.known_devices_files:
            device_list.WritePersistentDeviceList(
                path, [status['serial'] for status in statuses])

    # Write device info to file for buildbot info display.
    _WriteBuildbotFile(args.buildbot_path, statuses)

    # Dump the device statuses to JSON.
    if args.json_output:
        with open(args.json_output, 'wb') as f:
            f.write(
                json.dumps(statuses,
                           indent=4,
                           sort_keys=True,
                           separators=(',', ': ')))

    live_devices = [
        status['serial'] for status in statuses
        if (status['adb_status'] == 'device'
            and not IsDenylisted(status['serial'], denylist))
    ]

    # If all devices failed, or if there are no devices, it's an infra error.
    if not live_devices:
        logger.error('No available devices.')
    return 0 if live_devices else exit_codes.INFRA
    def testDenylistFileIsEmpty(self):
        try:
            with tempfile.NamedTemporaryFile(delete=False) as denylist_file:
                # Allow the temporary file to be closed.
                pass

            test_denylist = device_denylist.Denylist(denylist_file.name)
            self.assertEquals({}, test_denylist.Read())

        finally:
            if os.path.exists(denylist_file.name):
                os.remove(denylist_file.name)
Beispiel #12
0
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
def ProvisionDevices(devices,
                     denylist_file,
                     adb_key_files=None,
                     disable_location=False,
                     disable_mock_location=False,
                     disable_network=False,
                     disable_system_chrome=False,
                     emulators=False,
                     enable_java_debug=False,
                     max_battery_temp=None,
                     min_battery_level=None,
                     output_device_denylist=None,
                     reboot_timeout=None,
                     remove_system_webview=False,
                     system_app_remove_list=None,
                     system_package_remove_list=None,
                     wipe=True):
    denylist = (device_denylist.Denylist(denylist_file)
                if denylist_file else None)
    system_app_remove_list = system_app_remove_list or []
    system_package_remove_list = system_package_remove_list or []
    try:
        devices = script_common.GetDevices(devices, denylist)
    except device_errors.NoDevicesError:
        logging.error('No available devices to provision.')
        if denylist:
            logging.error('Local device denylist: %s', denylist.Read())
        raise
    devices = [d for d in devices if not emulators or d.adb.is_emulator]
    parallel_devices = device_utils.DeviceUtils.parallel(devices)

    steps = []
    if wipe:
        steps += [ProvisionStep(lambda d: Wipe(d, adb_key_files), reboot=True)]
    steps += [
        ProvisionStep(lambda d: SetProperties(
            d, enable_java_debug, disable_location, disable_mock_location),
                      reboot=not emulators)
    ]

    if disable_network:
        steps.append(ProvisionStep(DisableNetwork))

    if disable_system_chrome:
        steps.append(ProvisionStep(DisableSystemChrome))

    if max_battery_temp:
        steps.append(
            ProvisionStep(
                lambda d: WaitForBatteryTemperature(d, max_battery_temp)))

    if min_battery_level:
        steps.append(
            ProvisionStep(lambda d: WaitForCharge(d, min_battery_level)))

    if remove_system_webview:
        system_app_remove_list.extend(_SYSTEM_WEBVIEW_NAMES)

    if system_app_remove_list or system_package_remove_list:
        steps.append(
            ProvisionStep(lambda d: RemoveSystemApps(
                d, system_app_remove_list, system_package_remove_list)))

    steps.append(ProvisionStep(SetDate))
    steps.append(ProvisionStep(CheckExternalStorage))
    steps.append(ProvisionStep(StandaloneVrDeviceSetup))

    parallel_devices.pMap(ProvisionDevice, steps, denylist, reboot_timeout)

    denylisted_devices = denylist.Read() if denylist else []
    if output_device_denylist:
        with open(output_device_denylist, 'w') as f:
            json.dump(denylisted_devices, f)
    if all(d in denylisted_devices for d in devices):
        raise device_errors.NoDevicesError
    return 0
Beispiel #14
0
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.')
    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)
Beispiel #15
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('build_path', help='Path to android build.')
    parser.add_argument('-w',
                        '--wipe',
                        action='store_true',
                        help='If set, wipes user data')
    logging_common.AddLoggingArguments(parser)
    script_common.AddDeviceArguments(parser)
    args = parser.parse_args()
    logging_common.InitializeLogging(args)

    if args.denylist_file:
        denylist = device_denylist.Denylist(args.denylist_file).Read()
        if denylist:
            logger.critical('Device(s) in denylist, not flashing devices:')
            for key in denylist:
                logger.critical('  %s', key)
            return exit_codes.INFRA

    flashed_devices = []
    failed_devices = []

    def flash(device):
        try:
            device.FlashDevice(args.build_path, wipe=args.wipe)
            flashed_devices.append(device)
        except Exception:  # pylint: disable=broad-except
            logger.exception('Device %s failed to flash.', str(device))
            failed_devices.append(device)

    devices = []
    try:
        adb_devices = script_common.GetDevices(args.devices,
                                               args.denylist_file)
        devices += [
            fastboot_utils.FastbootUtils(device=d) for d in adb_devices
        ]
    except device_errors.NoDevicesError:
        # Don't bail out if we're not looking for any particular device and there's
        # at least one sitting in fastboot mode. Note that if we ARE looking for a
        # particular device, and it's in fastboot mode, this will still fail.
        fastboot_devices = fastboot.Fastboot.Devices()
        if args.devices or not fastboot_devices:
            raise
        devices += [
            fastboot_utils.FastbootUtils(fastbooter=d)
            for d in fastboot_devices
        ]

    parallel_devices = parallelizer.SyncParallelizer(devices)
    parallel_devices.pMap(flash)

    if flashed_devices:
        logger.info('The following devices were flashed:')
        logger.info('  %s', ' '.join(str(d) for d in flashed_devices))
    if failed_devices:
        logger.critical('The following devices failed to flash:')
        logger.critical('  %s', ' '.join(str(d) for d in failed_devices))
        return exit_codes.INFRA
    return 0
Beispiel #16
0
def main():
    custom_handler = logging.StreamHandler(sys.stdout)
    custom_handler.setFormatter(run_tests_helper.CustomFormatter())
    logging.getLogger().addHandler(custom_handler)
    logging.getLogger().setLevel(logging.INFO)

    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--device',
        help='The serial number of the device. If not specified '
        'will use all devices.')
    parser.add_argument('--denylist-file', help='Device denylist JSON file.')
    parser.add_argument('-a',
                        '--all-tombstones',
                        action='store_true',
                        help='Resolve symbols for all tombstones, rather than '
                        'just the most recent.')
    parser.add_argument('-s',
                        '--stack',
                        action='store_true',
                        help='Also include symbols for stack data')
    parser.add_argument(
        '-w',
        '--wipe-tombstones',
        action='store_true',
        help='Erase all tombstones from device after processing')
    parser.add_argument('-j',
                        '--jobs',
                        type=int,
                        default=4,
                        help='Number of jobs to use when processing multiple '
                        'crash stacks.')
    parser.add_argument('--output-directory',
                        help='Path to the root build directory.')
    parser.add_argument('--adb-path',
                        type=os.path.abspath,
                        help='Path to the adb binary.')
    args = parser.parse_args()

    if args.output_directory:
        constants.SetOutputDirectory(args.output_directory)

    devil_chromium.Initialize(output_directory=constants.GetOutDirectory(),
                              adb_path=args.adb_path)

    denylist = (device_denylist.Denylist(args.denylist_file)
                if args.denylist_file else None)

    if args.device:
        devices = [device_utils.DeviceUtils(args.device)]
    else:
        devices = device_utils.DeviceUtils.HealthyDevices(denylist)

    # This must be done serially because strptime can hit a race condition if
    # used for the first time in a multithreaded environment.
    # http://bugs.python.org/issue7980
    for device in devices:
        resolved_tombstones = ResolveTombstones(device, args.all_tombstones,
                                                args.stack,
                                                args.wipe_tombstones,
                                                args.jobs)
        for line in resolved_tombstones:
            logging.info(line)