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)
Exemple #3
0
    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
Exemple #4
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
Exemple #6
0
 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)
Exemple #8
0
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)
Exemple #11
0
    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
Exemple #13
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
Exemple #14
0
    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,
Exemple #15
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('--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)
Exemple #16
0
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))
Exemple #17
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',
        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)
Exemple #18
0
 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
Exemple #20
0
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
Exemple #21
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())