Exemple #1
0
  def _EditConfigs(self):
    android_avd_home = os.path.join(self._emulator_home, 'avd')
    avd_dir = os.path.join(android_avd_home, '%s.avd' % self._config.avd_name)

    config_path = os.path.join(avd_dir, 'config.ini')
    if os.path.exists(config_path):
      with open(config_path) as config_file:
        config_contents = ini.load(config_file)
    else:
      config_contents = {}

    config_contents['hw.sdCard'] = 'true'
    if self.avd_settings.sdcard.size:
      sdcard_path = os.path.join(avd_dir, 'cr-sdcard.img')
      if not os.path.exists(sdcard_path):
        mksdcard_path = os.path.join(
            os.path.dirname(self._emulator_path), 'mksdcard')
        mksdcard_cmd = [
            mksdcard_path,
            self.avd_settings.sdcard.size,
            sdcard_path,
        ]
        cmd_helper.RunCmd(mksdcard_cmd)

      config_contents['hw.sdCard.path'] = sdcard_path

    with open(config_path, 'w') as config_file:
      ini.dump(config_contents, config_file)
Exemple #2
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)
            avd_dir = os.path.join(android_avd_home,
                                   '%s.avd' % self._config.avd_name)
            config_ini = os.path.join(avd_dir, 'config.ini')

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

            if os.path.exists(config_ini):
                with open(config_ini) as config_ini_file:
                    config_ini_contents = ini.load(config_ini_file)
            else:
                config_ini_contents = {}
            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)

            config_ini_contents.update({
                'disk.dataPartition.size': '4G',
                'hw.lcd.density': density,
                'hw.lcd.height': height,
                'hw.lcd.width': width,
            })
            with open(config_ini, 'w') as config_ini_file:
                ini.dump(config_ini_contents, config_ini_file)

            # 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)
                    },
                ],
            }

            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,
                    ])
                if dry_run:
                    logging.info('Dry run. CIPD package creation skipped')
                else:
                    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)
Exemple #3
0
  def Start(self,
            read_only=True,
            snapshot_save=False,
            window=False,
            writable_system=False):
    """Starts the emulator running an instance of the given AVD."""

    with tempfile_ext.TemporaryFileName() as socket_path, (contextlib.closing(
        socket.socket(socket.AF_UNIX))) as sock:
      sock.bind(socket_path)
      emulator_cmd = [
          self._emulator_path,
          '-avd',
          self._avd_name,
          '-report-console',
          'unix:%s' % socket_path,
          '-no-boot-anim',
      ]

      android_avd_home = os.path.join(self._emulator_home, 'avd')
      avd_dir = os.path.join(android_avd_home, '%s.avd' % self._avd_name)

      hardware_qemu_path = os.path.join(avd_dir, 'hardware-qemu.ini')
      if os.path.exists(hardware_qemu_path):
        with open(hardware_qemu_path) as hardware_qemu_file:
          hardware_qemu_contents = ini.load(hardware_qemu_file)
      else:
        hardware_qemu_contents = {}

      if read_only:
        emulator_cmd.append('-read-only')
      if not snapshot_save:
        emulator_cmd.append('-no-snapshot-save')
      if writable_system:
        emulator_cmd.append('-writable-system')

      emulator_env = {}
      if self._emulator_home:
        emulator_env['ANDROID_EMULATOR_HOME'] = self._emulator_home
      if window:
        if 'DISPLAY' in os.environ:
          emulator_env['DISPLAY'] = os.environ.get('DISPLAY')
        else:
          raise AvdException('Emulator failed to start: DISPLAY not defined')
      else:
        emulator_cmd.append('-no-window')

      hardware_qemu_contents['hw.sdCard'] = 'true'
      if self._avd_config.avd_settings.sdcard.size:
        sdcard_path = os.path.join(self._emulator_home, 'avd',
                                   '%s.avd' % self._avd_name, 'cr-sdcard.img')
        if not os.path.exists(sdcard_path):
          mksdcard_path = os.path.join(
              os.path.dirname(self._emulator_path), 'mksdcard')
          mksdcard_cmd = [
              mksdcard_path,
              self._avd_config.avd_settings.sdcard.size,
              sdcard_path,
          ]
          cmd_helper.RunCmd(mksdcard_cmd)

        emulator_cmd.extend(['-sdcard', sdcard_path])
        hardware_qemu_contents['hw.sdCard.path'] = sdcard_path

      with open(hardware_qemu_path, 'w') as hardware_qemu_file:
        ini.dump(hardware_qemu_contents, hardware_qemu_file)

      sock.listen(1)

      logging.info('Starting emulator.')

      # TODO(jbudorick): Add support for logging emulator stdout & stderr at
      # higher logging levels.
      self._sink = open('/dev/null', 'w')
      self._emulator_proc = cmd_helper.Popen(
          emulator_cmd, stdout=self._sink, stderr=self._sink, env=emulator_env)

      # Waits for the emulator to report its serial as requested via
      # -report-console. See http://bit.ly/2lK3L18 for more.
      def listen_for_serial(s):
        logging.info('Waiting for connection from emulator.')
        with contextlib.closing(s.accept()[0]) as conn:
          val = conn.recv(1024)
          return 'emulator-%d' % int(val)

      try:
        self._emulator_serial = timeout_retry.Run(
            listen_for_serial, timeout=30, retries=0, args=[sock])
        logging.info('%s started', self._emulator_serial)
      except Exception as e:
        self.Stop()
        raise AvdException('Emulator failed to start: %s' % str(e))