def __init__(self, device, require_root):
        assert device, (
            'AndroidPlatformBackend can only be initialized from remote device'
        )
        super(AndroidPlatformBackend, self).__init__(device)
        self._device = device_utils.DeviceUtils(device.device_id)
        self._require_root = require_root
        if self._require_root:
            # Trying to root the device, if possible.
            if not self._device.HasRoot():
                try:
                    self._device.EnableRoot()
                except device_errors.CommandFailedError:
                    logging.warning('Unable to root %s', str(self._device))
            self._can_elevate_privilege = (self._device.HasRoot()
                                           or self._device.NeedsSU())
            assert self._can_elevate_privilege, (
                'Android device must have root access to run Telemetry')
            self._enable_performance_mode = device.enable_performance_mode
        else:
            self._enable_performance_mode = False
        self._battery = battery_utils.BatteryUtils(self._device)
        self._surface_stats_collector = None
        self._perf_tests_setup = perf_control.PerfControl(self._device)
        self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device)
        self._raw_display_frame_rate_measurements = []
        self._device_copy_script = None
        self._system_ui = None
        self._device_host_clock_offset = None
        self._video_recorder = None

        # TODO(https://crbug.com/1026296): Remove this once --chromium-output-dir
        # has a default value we can use.
        self._build_dir = util.GetUsedBuildDirectory()

        _FixPossibleAdbInstability()
Beispiel #2
0
  def __init__(self, device):
    assert device, (
        'AndroidPlatformBackend can only be initialized from remote device')
    super(AndroidPlatformBackend, self).__init__(device)
    self._device = device_utils.DeviceUtils(device.device_id)
    # Trying to root the device, if possible.
    if not self._device.HasRoot():
      try:
        self._device.EnableRoot()
      except device_errors.CommandFailedError:
        logging.warning('Unable to root %s', str(self._device))
    self._battery = battery_utils.BatteryUtils(self._device)
    self._enable_performance_mode = device.enable_performance_mode
    self._surface_stats_collector = None
    self._perf_tests_setup = perf_control.PerfControl(self._device)
    self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device)
    self._raw_display_frame_rate_measurements = []
    self._can_elevate_privilege = (
        self._device.HasRoot() or self._device.NeedsSU())
    self._device_copy_script = None
    self._power_monitor = (
      android_power_monitor_controller.AndroidPowerMonitorController([
        android_temperature_monitor.AndroidTemperatureMonitor(self._device),
        android_dumpsys_power_monitor.DumpsysPowerMonitor(
          self._battery, self),
        sysfs_power_monitor.SysfsPowerMonitor(self, standalone=True),
        android_fuelgauge_power_monitor.FuelGaugePowerMonitor(
            self._battery),
    ], self._battery))
    self._video_recorder = None
    self._installed_applications = None

    self._device_cert_util = None
    self._system_ui = None

    _FixPossibleAdbInstability()
Beispiel #3
0
import subprocess
import sys
import tempfile
import time

chrome_root = os.path.join(os.path.dirname(__file__), '../../..')
sys.path.insert(0, os.path.join(chrome_root, 'build/android'))
sys.path.insert(0, os.path.join(chrome_root, 'third_party/catapult/devil'))

from devil.android import device_utils
import pylib.utils.chrome_proxy_utils as chrome_proxy_utils

parser = argparse.ArgumentParser()
parser.add_argument('--device', required=True)
args = parser.parse_args()

wpr_record_path = tempfile.mkstemp(prefix='wprrecord', suffix='.wprgo')[1]

session = chrome_proxy_utils.ChromeProxySession()
session.wpr_record_mode = True
session.Start(device_utils.DeviceUtils(args.device), wpr_record_path)

print('Use these chrome flags:')
print(' '.join(session.GetFlags()))

print('Recording to', wpr_record_path)

# When this script exits, recording stops. Wait for one hour.
print('Press Ctrl+C to quit')
time.sleep(3600)
 def testGetDevices_missingDevice(self):
   with mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices',
                   return_value=[device_utils.DeviceUtils('123')]):
     with self.assertRaises(device_errors.DeviceUnreachableError):
       script_common.GetDevices(['456'], None)
Beispiel #5
0
def main():
    parser = argparse.ArgumentParser()
    AddArguments(parser)
    args = parser.parse_args()

    run_tests_helper.SetLogLevel(args.verbose)

    devil_dynamic_config = {
        'config_type': 'BaseConfig',
        'dependencies': {},
    }

    if args.adb_path:
        devil_dynamic_config['dependencies'].update({
            'adb': {
                'file_info': {
                    devil_env.GetPlatform(): {
                        'local_paths': [args.adb_path]
                    }
                }
            }
        })
    devil_env.config.Initialize(configs=[devil_dynamic_config])

    blacklist = (device_blacklist.Blacklist(args.blacklist_file)
                 if args.blacklist_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, blacklist)

    # 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))

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

    # If all devices failed, or if there are no devices, it's an infra error.
    return 0 if live_devices else exit_codes.INFRA
Beispiel #6
0
  def Create(self,
             force=False,
             snapshot=False,
             keep=False,
             cipd_json_output=None,
             dry_run=False):
    """Create an instance of the AVD CIPD package.

    This method:
     - installs the requisite system image
     - creates the AVD
     - modifies the AVD's ini files to support running chromium tests
       in chromium infrastructure
     - optionally starts & stops the AVD for snapshotting (default no)
     - By default creates and uploads an instance of the AVD CIPD package
       (can be turned off by dry_run flag).
     - optionally deletes the AVD (default yes)

    Args:
      force: bool indicating whether to force create the AVD.
      snapshot: bool indicating whether to snapshot the AVD before creating
        the CIPD package.
      keep: bool indicating whether to keep the AVD after creating
        the CIPD package.
      cipd_json_output: string path to pass to `cipd create` via -json-output.
      dry_run: When set to True, it will skip the CIPD package creation
        after creating the AVD.
    """
    logging.info('Installing required packages.')
    self._InstallCipdPackages(packages=[
        self._config.emulator_package,
        self._config.system_image_package,
    ])

    android_avd_home = os.path.join(self._emulator_home, 'avd')

    if not os.path.exists(android_avd_home):
      os.makedirs(android_avd_home)

    avd_manager = _AvdManagerAgent(
        avd_home=android_avd_home, sdk_root=self._emulator_sdk_root)

    logging.info('Creating AVD.')
    avd_manager.Create(
        avd_name=self._config.avd_name,
        system_image=self._config.system_image_name,
        force=force)

    try:
      logging.info('Modifying AVD configuration.')

      # Clear out any previous configuration or state from this AVD.
      root_ini = os.path.join(android_avd_home,
                              '%s.ini' % self._config.avd_name)
      features_ini = os.path.join(self._emulator_home, 'advancedFeatures.ini')
      avd_dir = os.path.join(android_avd_home, '%s.avd' % self._config.avd_name)
      config_ini = os.path.join(avd_dir, 'config.ini')

      with ini.update_ini_file(root_ini) as root_ini_contents:
        root_ini_contents['path.rel'] = 'avd/%s.avd' % self._config.avd_name

      with ini.update_ini_file(features_ini) as features_ini_contents:
        # features_ini file will not be refreshed by avdmanager during
        # creation. So explicitly clear its content to exclude any leftover
        # from previous creation.
        features_ini_contents.clear()
        features_ini_contents.update(self.avd_settings.advanced_features)

      with ini.update_ini_file(config_ini) as config_ini_contents:
        height = self.avd_settings.screen.height or _DEFAULT_SCREEN_HEIGHT
        width = self.avd_settings.screen.width or _DEFAULT_SCREEN_WIDTH
        density = self.avd_settings.screen.density or _DEFAULT_SCREEN_DENSITY

        config_ini_contents.update({
            'disk.dataPartition.size': '4G',
            'hw.keyboard': 'yes',
            'hw.lcd.density': density,
            'hw.lcd.height': height,
            'hw.lcd.width': width,
        })

        if self.avd_settings.ram_size:
          config_ini_contents['hw.ramSize'] = self.avd_settings.ram_size

      # Start & stop the AVD.
      self._Initialize()
      instance = _AvdInstance(self._emulator_path, self._emulator_home,
                              self._config)
      # Enable debug for snapshot when it is set to True
      debug_tags = 'init,snapshot' if snapshot else None
      instance.Start(
          read_only=False, snapshot_save=snapshot, debug_tags=debug_tags)
      # Android devices with full-disk encryption are encrypted on first boot,
      # and then get decrypted to continue the boot process (See details in
      # https://bit.ly/3agmjcM).
      # Wait for this step to complete since it can take a while for old OSs
      # like M, otherwise the avd may have "Encryption Unsuccessful" error.
      device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted(
          decrypt=True, timeout=180, retries=0)
      instance.Stop()

      # The multiinstance lock file seems to interfere with the emulator's
      # operation in some circumstances (beyond the obvious -read-only ones),
      # and there seems to be no mechanism by which it gets closed or deleted.
      # See https://bit.ly/2pWQTH7 for context.
      multiInstanceLockFile = os.path.join(avd_dir, 'multiinstance.lock')
      if os.path.exists(multiInstanceLockFile):
        os.unlink(multiInstanceLockFile)

      package_def_content = {
          'package':
          self._config.avd_package.package_name,
          'root':
          self._emulator_home,
          'install_mode':
          'copy',
          'data': [{
              'dir': os.path.relpath(avd_dir, self._emulator_home)
          }, {
              'file': os.path.relpath(root_ini, self._emulator_home)
          }, {
              'file': os.path.relpath(features_ini, self._emulator_home)
          }],
      }

      logging.info('Creating AVD CIPD package.')
      logging.debug('ensure file content: %s',
                    json.dumps(package_def_content, indent=2))

      with tempfile_ext.TemporaryFileName(suffix='.json') as package_def_path:
        with open(package_def_path, 'w') as package_def_file:
          json.dump(package_def_content, package_def_file)

        logging.info('  %s', self._config.avd_package.package_name)
        cipd_create_cmd = [
            'cipd',
            'create',
            '-pkg-def',
            package_def_path,
            '-tag',
            'emulator_version:%s' % self._config.emulator_package.version,
            '-tag',
            'system_image_version:%s' %
            self._config.system_image_package.version,
        ]
        if cipd_json_output:
          cipd_create_cmd.extend([
              '-json-output',
              cipd_json_output,
          ])
        logging.info('running %r%s', cipd_create_cmd,
                     ' (dry_run)' if dry_run else '')
        if not dry_run:
          try:
            for line in cmd_helper.IterCmdOutputLines(cipd_create_cmd):
              logging.info('    %s', line)
          except subprocess.CalledProcessError as e:
            raise AvdException(
                'CIPD package creation failed: %s' % str(e),
                command=cipd_create_cmd)

    finally:
      if not keep:
        logging.info('Deleting AVD.')
        avd_manager.Delete(avd_name=self._config.avd_name)
 def setUp(self):
     super(TestPerfControl, self).setUp()
     if not os.getenv('BUILDTYPE'):
         os.environ['BUILDTYPE'] = 'Debug'
     self._device = device_utils.DeviceUtils(self.serial)
Beispiel #8
0
 def testInitWithDeviceUtil(self):
     serial = '0fedcba987654321'
     d = device_utils.DeviceUtils(serial)
     b = battery_utils.BatteryUtils(d)
     self.assertEqual(d, b._device)
Beispiel #9
0
 def setUp(self):
   super(DeviceUtilsPushDeleteFilesTest, self).setUp()
   self.adb = adb_wrapper.AdbWrapper(self.serial)
   self.adb.WaitForDevice()
   self.device = device_utils.DeviceUtils(
       self.adb, default_timeout=10, default_retries=0)
 def _GetMockDeviceUtils(self, device_serial, is_online=True):
   device = device_utils.DeviceUtils(device_serial)
   device.IsOnline = mock.MagicMock(return_value=is_online)
   return device
Beispiel #11
0
 def device(self):
     if not self._emulator_device and self._emulator_serial:
         self._emulator_device = device_utils.DeviceUtils(
             self._emulator_serial)
     return self._emulator_device
 def StartAgentTracing(self, config, timeout=None):
     self._device = device_utils.DeviceUtils(config.device_serial_number)
     self._trace_data += self._get_process_snapshot()
     return True
                      help='Path to known presentation.device lists.')
  parser.add_argument('--enable-usb-reset', action='store_true',
                      help='Reset USB if necessary.')
  parser.add_argument('-v', '--verbose', action='count', default=1,
                      help='Log more information.')

  args = parser.parse_args()
  run_tests_helper.SetLogLevel(args.verbose)

  devil_dynamic_config = devil_env.EmptyConfig()
  if args.adb_path:
    devil_dynamic_config['dependencies'].update(
        devil_env.LocalConfigItem(
            'adb', devil_env.GetPlatform(), args.adb_path))
  devil_env.config.Initialize(configs=[devil_dynamic_config])

  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
               if args.blacklist_file
               else None)

  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, blacklist, enable_usb_reset=args.enable_usb_reset)


if __name__ == '__main__':
  sys.exit(presentation.main())
Beispiel #14
0
    def Create(self,
               force=False,
               snapshot=False,
               keep=False,
               cipd_json_output=None):
        """Create an instance of the AVD CIPD package.

    This method:
     - installs the requisite system image
     - creates the AVD
     - modifies the AVD's ini files to support running chromium tests
       in chromium infrastructure
     - optionally starts & stops the AVD for snapshotting (default no)
     - creates and uploads an instance of the AVD CIPD package
     - optionally deletes the AVD (default yes)

    Args:
      force: bool indicating whether to force create the AVD.
      snapshot: bool indicating whether to snapshot the AVD before creating
        the CIPD package.
      keep: bool indicating whether to keep the AVD after creating
        the CIPD package.
      cipd_json_output: string path to pass to `cipd create` via -json-output.
    """
        logging.info('Installing required packages.')
        self.Install(packages=[
            self._config.emulator_package,
            self._config.system_image_package,
        ])

        android_avd_home = os.path.join(self._emulator_home, 'avd')

        if not os.path.exists(android_avd_home):
            os.makedirs(android_avd_home)

        avd_manager = _AvdManagerAgent(avd_home=android_avd_home,
                                       sdk_root=self._emulator_sdk_root)

        logging.info('Creating AVD.')
        avd_manager.Create(avd_name=self._config.avd_name,
                           system_image=self._config.system_image_name,
                           force=force)

        try:
            logging.info('Modifying AVD configuration.')

            root_ini = os.path.join(android_avd_home,
                                    '%s.ini' % self._config.avd_name)
            avd_dir = os.path.join(android_avd_home,
                                   '%s.avd' % self._config.avd_name)
            config_ini = os.path.join(avd_dir, 'config.ini')

            with open(root_ini, 'a') as root_ini_file:
                root_ini_file.write('path.rel=avd/%s.avd\n' %
                                    self._config.avd_name)

            with open(config_ini, 'a') as config_ini_file:
                config_ini_file.write('disk.dataPartition.size=4G\n')

            # Start & stop the AVD.
            self._Initialize()
            instance = _AvdInstance(self._emulator_path, self._config.avd_name,
                                    self._emulator_home)
            instance.Start(read_only=not snapshot)
            device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted(
                timeout=180, retries=0)
            instance.Stop()

            package_def_content = {
                'package':
                self._config.avd_package.package_name,
                'root':
                self._emulator_home,
                'install_mode':
                'copy',
                'data': [
                    {
                        'dir': os.path.relpath(avd_dir, self._emulator_home)
                    },
                    {
                        'file': os.path.relpath(root_ini, self._emulator_home)
                    },
                ],
            }

            logging.info('Creating AVD CIPD package.')
            logging.debug('ensure file content: %s',
                          json.dumps(package_def_content, indent=2))

            with tempfile_ext.TemporaryFileName(
                    suffix='.json') as package_def_path:
                with open(package_def_path, 'w') as package_def_file:
                    json.dump(package_def_content, package_def_file)

                logging.info('  %s', self._config.avd_package.package_name)
                cipd_create_cmd = [
                    'cipd',
                    'create',
                    '-pkg-def',
                    package_def_path,
                ]
                if cipd_json_output:
                    cipd_create_cmd.extend([
                        '-json-output',
                        cipd_json_output,
                    ])
                try:
                    for line in cmd_helper.IterCmdOutputLines(cipd_create_cmd):
                        logging.info('    %s', line)
                except subprocess.CalledProcessError as e:
                    raise AvdException('CIPD package creation failed: %s' %
                                       str(e),
                                       command=cipd_create_cmd)

        finally:
            if not keep:
                logging.info('Deleting AVD.')
                avd_manager.Delete(avd_name=self._config.avd_name)
Beispiel #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)
Beispiel #16
0
 def setUp(self):
   super(PsOutputCompatibilityTests, self).setUp()
   self.adb = adb_wrapper.AdbWrapper(self.serial)
   self.adb.WaitForDevice()
   self.device = device_utils.DeviceUtils(self.adb, default_retries=0)
Beispiel #17
0
 def __init__(self, configuration):
   self.id = configuration['id']
   self.description = configuration['description']
   self.install_metadata = configuration['install_metadata']
   self.device = device_utils.DeviceUtils(self.id)
def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('--out-dir',
                      help='Directory where the device path is stored',
                      default=os.path.join(constants.DIR_SOURCE_ROOT, 'out'))
  parser.add_argument('--restart-usb', action='store_true',
                      help='DEPRECATED. '
                           'This script now always tries to reset USB.')
  parser.add_argument('--json-output',
                      help='Output JSON information into a specified file.')
  parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
  parser.add_argument('-v', '--verbose', action='count', default=1,
                      help='Log more information.')

  args = parser.parse_args()

  run_tests_helper.SetLogLevel(args.verbose)

  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
               if args.blacklist_file
               else None)

  last_devices_path = os.path.join(
      args.out_dir, device_list.LAST_DEVICES_FILENAME)
  try:
    expected_devices = set(
        device_list.GetPersistentDeviceList(last_devices_path))
  except IOError:
    expected_devices = set()

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

  RecoverDevices(devices, blacklist)
  statuses = DeviceStatus(devices, blacklist)

  # Log the state of all devices.
  for status in statuses:
    logging.info(status['serial'])
    adb_status = status.get('adb_status')
    blacklisted = status.get('blacklisted')
    logging.info('  USB status: %s',
                 'online' if status.get('usb_status') else 'offline')
    logging.info('  ADB status: %s', adb_status)
    logging.info('  Blacklisted: %s', str(blacklisted))
    if adb_status == 'device' and not blacklisted:
      logging.info('  Device type: %s', status.get('ro.build.product'))
      logging.info('  OS build: %s', status.get('ro.build.id'))
      logging.info('  OS build fingerprint: %s',
                   status.get('ro.build.fingerprint'))
      logging.info('  Battery state:')
      for k, v in status.get('battery', {}).iteritems():
        logging.info('    %s: %s', k, v)
      logging.info('  IMEI slice: %s', status.get('imei_slice'))
      logging.info('  WiFi IP: %s', status.get('wifi_ip'))

  # Update the last devices file.
  device_list.WritePersistentDeviceList(
      last_devices_path,
      [status['serial'] for status in statuses])

  # Write device info to file for buildbot info display.
  if os.path.exists('/home/chrome-bot'):
    with open('/home/chrome-bot/.adb_device_info', 'w') as f:
      for status in statuses:
        try:
          if status['adb_status'] == 'device':
            f.write('{serial} {adb_status} {build_product} {build_id} '
                    '{temperature:.1f}C {level}%\n'.format(
                serial=status['serial'],
                adb_status=status['adb_status'],
                build_product=status['type'],
                build_id=status['build'],
                temperature=float(status['battery']['temperature']) / 10,
                level=status['battery']['level']
            ))
          else:
            f.write('{serial} {adb_status}'.format(
                serial=status['serial'],
                adb_status=status['adb_status']
            ))
        except Exception: # pylint: disable=broad-except
          pass

  # 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))

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

  # If all devices failed, or if there are no devices, it's an infra error.
  return 0 if live_devices else constants.INFRA_EXIT_CODE
Beispiel #19
0
 def setUp(self):
     super(DeviceCrashTest, self).setUp()
     self.device = device_utils.DeviceUtils(self.serial)
Beispiel #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
Beispiel #21
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--json-output',
                        help='Output JSON information into a specified file.')
    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('--known-devices-file',
                        action='append',
                        default=[],
                        dest='known_devices_files',
                        help='Path to known device lists.')
    parser.add_argument('--buildbot-path',
                        '-b',
                        default='/home/chrome-bot/.adb_device_info',
                        help='Absolute path to buildbot file location')
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=1,
                        help='Log more information.')
    parser.add_argument('-w',
                        '--overwrite-known-devices-files',
                        action='store_true',
                        help='If set, overwrites known devices files wiht new '
                        'values.')

    args = parser.parse_args()

    run_tests_helper.SetLogLevel(args.verbose)

    devil_custom_deps = None
    if args.adb_path:
        devil_custom_deps = {
            'adb': {
                devil_env.GetPlatform(): [args.adb_path],
            },
        }
    devil_env.config.Initialize(configs=devil_custom_deps)

    blacklist = (device_blacklist.Blacklist(args.blacklist_file)
                 if args.blacklist_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, blacklist)

    # 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))

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

    # If all devices failed, or if there are no devices, it's an infra error.
    return 0 if live_devices else exit_codes.INFRA
Beispiel #22
0
 def _GetMockDeviceUtils(self, device_serial):
     device = device_utils.DeviceUtils(device_serial)
     return device
Beispiel #23
0
    def Create(self,
               force=False,
               snapshot=False,
               keep=False,
               cipd_json_output=None):
        """Create an instance of the AVD CIPD package.

    This method:
     - installs the requisite system image
     - creates the AVD
     - modifies the AVD's ini files to support running chromium tests
       in chromium infrastructure
     - optionally starts & stops the AVD for snapshotting (default no)
     - creates and uploads an instance of the AVD CIPD package
     - optionally deletes the AVD (default yes)

    Args:
      force: bool indicating whether to force create the AVD.
      snapshot: bool indicating whether to snapshot the AVD before creating
        the CIPD package.
      keep: bool indicating whether to keep the AVD after creating
        the CIPD package.
      cipd_json_output: string path to pass to `cipd create` via -json-output.
    """
        logging.info('Installing required packages.')
        self.Install(packages=[
            self._config.emulator_package,
            self._config.system_image_package,
        ])

        android_avd_home = os.path.join(self._emulator_home, 'avd')

        if not os.path.exists(android_avd_home):
            os.makedirs(android_avd_home)

        avd_manager = _AvdManagerAgent(avd_home=android_avd_home,
                                       sdk_root=self._emulator_sdk_root)

        logging.info('Creating AVD.')
        avd_manager.Create(avd_name=self._config.avd_name,
                           system_image=self._config.system_image_name,
                           force=force,
                           sdcard=self._config.avd_settings.sdcard.size)

        try:
            logging.info('Modifying AVD configuration.')

            # Clear out any previous configuration or state from this AVD.
            root_ini = os.path.join(android_avd_home,
                                    '%s.ini' % self._config.avd_name)
            avd_dir = os.path.join(android_avd_home,
                                   '%s.avd' % self._config.avd_name)
            config_ini = os.path.join(avd_dir, 'config.ini')

            with open(root_ini, 'a') as root_ini_file:
                root_ini_file.write('path.rel=avd/%s.avd\n' %
                                    self._config.avd_name)

            height = (self._config.avd_settings.screen.height
                      or _DEFAULT_SCREEN_HEIGHT)
            width = (self._config.avd_settings.screen.width
                     or _DEFAULT_SCREEN_WIDTH)
            density = (self._config.avd_settings.screen.density
                       or _DEFAULT_SCREEN_DENSITY)

            with open(config_ini, 'a') as config_ini_file:
                config_ini_contents = _CONFIG_INI_CONTENTS.format(
                    density=density, height=height, width=width)
                config_ini_file.write(config_ini_contents)

            # Start & stop the AVD.
            self._Initialize()
            instance = _AvdInstance(self._emulator_path, self._config.avd_name,
                                    self._emulator_home)
            instance.Start(read_only=False, snapshot_save=snapshot)
            device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted(
                timeout=180, retries=0)
            instance.Stop()

            # The multiinstance lock file seems to interfere with the emulator's
            # operation in some circumstances (beyond the obvious -read-only ones),
            # and there seems to be no mechanism by which it gets closed or deleted.
            # See https://bit.ly/2pWQTH7 for context.
            multiInstanceLockFile = os.path.join(avd_dir, 'multiinstance.lock')
            if os.path.exists(multiInstanceLockFile):
                os.unlink(multiInstanceLockFile)

            package_def_content = {
                'package':
                self._config.avd_package.package_name,
                'root':
                self._emulator_home,
                'install_mode':
                'copy',
                'data': [
                    {
                        'dir': os.path.relpath(avd_dir, self._emulator_home)
                    },
                    {
                        'file': os.path.relpath(root_ini, self._emulator_home)
                    },
                ],
            }

            logging.info('Creating AVD CIPD package.')
            logging.debug('ensure file content: %s',
                          json.dumps(package_def_content, indent=2))

            with tempfile_ext.TemporaryFileName(
                    suffix='.json') as package_def_path:
                with open(package_def_path, 'w') as package_def_file:
                    json.dump(package_def_content, package_def_file)

                logging.info('  %s', self._config.avd_package.package_name)
                cipd_create_cmd = [
                    'cipd',
                    'create',
                    '-pkg-def',
                    package_def_path,
                ]
                if cipd_json_output:
                    cipd_create_cmd.extend([
                        '-json-output',
                        cipd_json_output,
                    ])
                try:
                    for line in cmd_helper.IterCmdOutputLines(cipd_create_cmd):
                        logging.info('    %s', line)
                except subprocess.CalledProcessError as e:
                    raise AvdException('CIPD package creation failed: %s' %
                                       str(e),
                                       command=cipd_create_cmd)

        finally:
            if not keep:
                logging.info('Deleting AVD.')
                avd_manager.Delete(avd_name=self._config.avd_name)
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--out-dir',
                        help='Directory where the device path is stored',
                        default=os.path.join(host_paths.DIR_SOURCE_ROOT,
                                             'out'))
    parser.add_argument('--restart-usb',
                        action='store_true',
                        help='DEPRECATED. '
                        'This script now always tries to reset USB.')
    parser.add_argument('--json-output',
                        help='Output JSON information into a specified file.')
    parser.add_argument('--adb-path',
                        type=os.path.abspath,
                        help='Absolute path to the adb binary to use.')
    parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
    parser.add_argument('--known-devices-file',
                        action='append',
                        default=[],
                        dest='known_devices_files',
                        help='Path to known device lists.')
    parser.add_argument('-v',
                        '--verbose',
                        action='count',
                        default=1,
                        help='Log more information.')

    args = parser.parse_args()

    run_tests_helper.SetLogLevel(args.verbose)

    devil_chromium.Initialize(adb_path=args.adb_path)

    blacklist = (device_blacklist.Blacklist(args.blacklist_file)
                 if args.blacklist_file else None)

    expected_devices = set()
    try:
        for path in args.known_devices_files:
            if os.path.exists(path):
                expected_devices.update(
                    device_list.GetPersistentDeviceList(path))
    except IOError:
        logging.warning('Problem reading %s, skipping.', path)

    logging.info('Expected devices:')
    for device in expected_devices:
        logging.info('  %s', device)

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

    RecoverDevices(devices, blacklist)
    statuses = DeviceStatus(devices, blacklist)

    # Log the state of all devices.
    for status in statuses:
        logging.info(status['serial'])
        adb_status = status.get('adb_status')
        blacklisted = status.get('blacklisted')
        logging.info('  USB status: %s',
                     'online' if status.get('usb_status') else 'offline')
        logging.info('  ADB status: %s', adb_status)
        logging.info('  Blacklisted: %s', str(blacklisted))
        if adb_status == 'device' and not blacklisted:
            logging.info('  Device type: %s', status.get('ro.build.product'))
            logging.info('  OS build: %s', status.get('ro.build.id'))
            logging.info('  OS build fingerprint: %s',
                         status.get('ro.build.fingerprint'))
            logging.info('  Battery state:')
            for k, v in status.get('battery', {}).iteritems():
                logging.info('    %s: %s', k, v)
            logging.info('  IMEI slice: %s', status.get('imei_slice'))
            logging.info('  WiFi IP: %s', status.get('wifi_ip'))

    # Update the last devices file(s).
    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.
    if os.path.exists('/home/chrome-bot'):
        with open('/home/chrome-bot/.adb_device_info', 'w') as f:
            for status in statuses:
                try:
                    if status['adb_status'] == 'device':
                        f.write(
                            '{serial} {adb_status} {build_product} {build_id} '
                            '{temperature:.1f}C {level}%\n'.format(
                                serial=status['serial'],
                                adb_status=status['adb_status'],
                                build_product=status['type'],
                                build_id=status['build'],
                                temperature=float(
                                    status['battery']['temperature']) / 10,
                                level=status['battery']['level']))
                    elif status.get('usb_status', False):
                        f.write('{serial} {adb_status}\n'.format(
                            serial=status['serial'],
                            adb_status=status['adb_status']))
                    else:
                        f.write('{serial} offline\n'.format(
                            serial=status['serial']))
                except Exception:  # pylint: disable=broad-except
                    pass

    # 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))

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

    # If all devices failed, or if there are no devices, it's an infra error.
    if not live_devices:
        logging.error('No available devices.')
    return 0 if live_devices else exit_codes.INFRA
Beispiel #25
0
import os
import subprocess
import sys
import time

chrome_root = os.path.join(os.path.dirname(__file__), '../../..')
sys.path.insert(0, os.path.join(chrome_root, 'build/android'))
# Note that catapult/devil appears to require python2.
sys.path.insert(0, os.path.join(chrome_root, 'third_party/catapult/devil'))

from devil.android import device_utils
import pylib.utils.chrome_proxy_utils as chrome_proxy_utils

parser = argparse.ArgumentParser()
parser.add_argument('--device', required=True)
parser.add_argument('--replay-file', required=True)
args = parser.parse_args()

session = chrome_proxy_utils.ChromeProxySession()
session.wpr_record_mode = False
session.Start(device_utils.DeviceUtils(args.device), args.replay_file)

print('Use these chrome flags:')
print(' '.join(session.GetFlags()))

print('Replaying ', args.replay_file)

# When this script exits, replaying stops. Wait for one hour.
print('Press Ctrl+C to quit')
time.sleep(3600)
Beispiel #26
0
def main(argv):
  parser = argparse.ArgumentParser()
  parser.add_argument('--process',
                      dest='procname',
                      help="A (sub)string to match against process names.")
  parser.add_argument('-p',
                      '--pid',
                      dest='pid',
                      type=Validator.ValidateNonNegativeNumber,
                      help='Which pid to scan for.')
  parser.add_argument('-d',
                      '--device',
                      dest='device',
                      help='Device serial to scan.')
  parser.add_argument('-t',
                      '--timelimit',
                      dest='timelimit',
                      type=Validator.ValidateNonNegativeNumber,
                      help='How long to track memory in seconds.')
  parser.add_argument('-f',
                      '--frequency',
                      dest='frequency',
                      default=0,
                      type=Validator.ValidateNonNegativeNumber,
                      help='How often to poll in seconds.')
  parser.add_argument('-s',
                      '--diff-against-start',
                      dest='diff_against_start',
                      action='store_true',
                      help='Whether or not to always compare against the'
                           ' original memory values for deltas.')
  parser.add_argument('-b',
                      '--boring-output',
                      dest='dull_output',
                      action='store_true',
                      help='Whether or not to dull down the output.')
  parser.add_argument('-k',
                      '--keep-results',
                      dest='no_overwrite',
                      action='store_true',
                      help='Keeps printing the results in a list instead of'
                           ' overwriting the previous values.')
  parser.add_argument('-g',
                      '--graph-file',
                      dest='graph_file',
                      type=Validator.ValidatePdfPath,
                      help='PDF file to save graph of memory stats to.')
  parser.add_argument('-o',
                      '--text-file',
                      dest='text_file',
                      type=Validator.ValidatePath,
                      help='File to save memory tracking stats to.')
  parser.add_argument('-m',
                      '--memory',
                      dest='show_mem',
                      action='store_true',
                      help='Whether or not to show memory stats. True by'
                           ' default unless --n is specified.')
  parser.add_argument('-n',
                      '--net',
                      dest='show_net',
                      action='store_true',
                      help='Whether or not to show network stats. False by'
                           ' default.')

  args = parser.parse_args()

  # Add a basic filter to make sure we search for something.
  if not args.procname and not args.pid:
    args.procname = 'chrome'

  # Make sure we show memory stats if nothing was specifically requested.
  if not args.show_net and not args.show_mem:
    args.show_mem = True

  devil_chromium.Initialize()

  curses.setupterm()

  printer = OutputBeautifier(not args.dull_output, not args.no_overwrite)

  sys.stdout.write("Running... Hold CTRL-C to stop (or specify timeout).\n")
  try:
    last_time = time.time()

    adb = None
    old_snapshot = None
    snapshots = []
    while not args.timelimit or Timer.GetTimestamp() < float(args.timelimit):
      # Check if we need to track another device
      device = DeviceHelper.GetDeviceToTrack(args.device)
      if not device:
        adb = None
      elif not adb or device != str(adb):
        #adb = adb_wrapper.AdbWrapper(device)
        adb = device_utils.DeviceUtils(device)
        old_snapshot = None
        snapshots = []
        try:
          adb.EnableRoot()
        except device_errors.CommandFailedError:
          sys.stderr.write('Unable to run adb as root.\n')
          sys.exit(1)

      # Grab a snapshot if we have a device
      snapshot = None
      if adb:
        pids = DeviceHelper.GetPidsToTrack(adb, args.pid, args.procname)
        snapshot = None
        if pids:
          snapshot = DeviceSnapshot(adb, pids, args.show_mem, args.show_net)

      if snapshot and snapshot.HasResults():
        snapshots.append(snapshot)

      printer.PrettyPrint(snapshot, old_snapshot, args.show_mem, args.show_net)

      # Transfer state for the next iteration and sleep
      delay = max(1, args.frequency)
      if snapshot:
        delay = max(0, args.frequency - (time.time() - last_time))
      time.sleep(delay)

      last_time = time.time()
      if not old_snapshot or not args.diff_against_start:
        old_snapshot = snapshot
  except KeyboardInterrupt:
    pass

  if args.graph_file:
    printer.PrettyGraph(args.graph_file, snapshots)

  if args.text_file:
    printer.PrettyFile(args.text_file,
                       snapshots,
                       args.diff_against_start,
                       args.show_mem,
                       args.show_net)
Beispiel #27
0
 def _GetMockDeviceUtils(self, device_serial):
     presentation.device = device_utils.DeviceUtils(device_serial)
     return presentation.device
Beispiel #28
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('--blacklist-file', help='Device blacklist 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()

    devil_chromium.Initialize(adb_path=args.adb_path)

    blacklist = (device_blacklist.Blacklist(args.blacklist_file)
                 if args.blacklist_file else None)

    if args.output_directory:
        constants.SetOutputDirectory(args.output_directory)
    # Do an up-front test that the output directory is known.
    constants.CheckOutputDirectory()

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

    # 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)
Beispiel #29
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())