Example #1
0
    def test_tracing(self):
        TRACE_BUFFER_SIZE = '16384'
        TRACE_TIME = '5'

        devices = device_utils.DeviceUtils.HealthyDevices()
        package_info = util.get_supported_browsers()['stable']
        device = devices[0]
        with tempfile_ext.TemporaryFileName() as output_file_name:
            # Launch the browser before tracing.
            device.StartActivity(intent.Intent(activity=package_info.activity,
                                               package=package_info.package,
                                               data='about:blank',
                                               extras={'create_new_tab':
                                                       True}),
                                 blocking=True,
                                 force_stop=True)

            # Run atrace agent.
            run_systrace.main_impl([
                './run_systrace.py', '-b', TRACE_BUFFER_SIZE, '-t', TRACE_TIME,
                '-o', output_file_name, '-e',
                str(device), '--atrace-categories=gfx,input,view'
            ])

            # Verify results.
            with open(output_file_name, 'r') as f:
                full_trace = f.read()
            self.assertTrue('CPU#' in full_trace)
Example #2
0
 def testAddTraceDataAndSerialize(self):
   with tempfile_ext.TemporaryFileName() as trace_path:
     with trace_data.TraceDataBuilder() as builder:
       builder.AddTraceFor(trace_data.CHROME_TRACE_PART,
                           {'traceEvents': [1, 2, 3]})
       builder.Serialize(trace_path)
       self.assertTrue(os.path.exists(trace_path))
       self.assertGreater(os.stat(trace_path).st_size, 0)  # File not empty.
Example #3
0
 def _test_trace(self, disable=True, format=None):
     with tempfile_ext.TemporaryFileName() as filename:
         self._log_path = filename
         try:
             trace_event.trace_enable(self._log_path, format=format)
             yield
         finally:
             if disable:
                 trace_event.trace_disable()
Example #4
0
    def Start(self, read_only=True, snapshot_save=False, window=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,
            ]
            if read_only:
                emulator_cmd.append('-read-only')
            if not snapshot_save:
                emulator_cmd.append('-no-snapshot-save')
            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')
            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))
  def testTemporaryFileName(self):
    with tempfile_ext.TemporaryFileName('foo') as filepath:
      self.assertTrue(os.path.basename(filepath), 'foo')
      self.assertFalse(os.path.exists(filepath))

      with open(filepath, 'w') as f:
        f.write('<data>')
      self.assertTrue(os.path.exists(filepath))

      shutil.copyfile(filepath, filepath + '.bak')
      self.assertTrue(filecmp.cmp(filepath, filepath + '.bak'))

    self.assertFalse(os.path.exists(filepath))
    self.assertFalse(os.path.exists(os.path.dirname(filepath)))
Example #6
0
def _SerializeAndProcessTrace(trace_builder, process_trace_func_code):
    """Load data into a trace model and run a query on it.

  The current implementation works by loading the trace data into the TBMv2,
  i.e. JavaScript based, timeline model. But this is an implementation detail,
  clients for the public methods of this module should remain agnostic about
  the model being used for trace processing.
  """
    with tempfile_ext.TemporaryFileName() as trace_file:
        try:
            trace_builder.Serialize(trace_file)
            return map_single_trace.ExecuteTraceMappingCode(
                trace_file, process_trace_func_code)
        finally:
            trace_builder.CleanUpTraceData()
Example #7
0
 def go(self, cb):
     """
 Enables tracing, runs the provided callback, and if successful, returns a
 TraceEvents object with the results.
 """
     with tempfile_ext.TemporaryFileName() as filename:
         self._file = open(filename, 'a+')
         trace_enable(self._file)
         try:
             cb()
         finally:
             trace_disable()
         e = ParsedTraceEvents(trace_filename=self._file.name)
         self._file.close()
         self._file = None
     return e
Example #8
0
def ExtractApks(output_dir,
                apks_path,
                abis,
                locales,
                features,
                pixel_density,
                sdk_version,
                modules=None):
    """Extracts splits from APKS archive.

  Args:
    output_dir: Directory to extract splits into.
    apks_path: Path to APKS archive.
    abis: ABIs to support.
    locales: Locales to support.
    features: Device features to support.
    pixel_density: Pixel density to support.
    sdk_version: Target SDK version.
    modules: Extra modules to install.
  """
    device_spec = {
        'supportedAbis': abis,
        'supportedLocales': ['%s-%s' % l for l in locales],
        'deviceFeatures': features,
        'screenDensity': pixel_density,
        'sdkVersion': sdk_version,
    }
    with tempfile_ext.TemporaryFileName(suffix='.json') as device_spec_path:
        with open(device_spec_path, 'w') as f:
            json.dump(device_spec, f)
        cmd = [
            'java',
            '-jar',
            _bundletool_path.read(),
            'extract-apks',
            '--apks=%s' % apks_path,
            '--device-spec=%s' % device_spec_path,
            '--output-dir=%s' % output_dir,
        ]
        if modules:
            cmd += ['--modules=%s' % ','.join(modules)]
        status, stdout, stderr = cmd_helper.GetCmdStatusOutputAndError(cmd)
        if status != 0:
            raise base_error.BaseError(
                'Failed running {} with output\n{}\n{}'.format(
                    ' '.join(cmd), stdout, stderr))
Example #9
0
 def testAsDictWhenTraceSerializedAndUploaded(self, insert_mock):
     with tempfile_ext.TemporaryFileName('test.html') as file_path:
         with trace.TraceValue(
                 None,
                 trace_data.CreateTestTrace(),
                 file_path=file_path,
                 upload_bucket=trace.cloud_storage.PUBLIC_BUCKET,
                 remote_path='a.html',
                 cloud_url='http://example.com/a.html') as v:
             v.SerializeTraceData()
             fh = v.Serialize()
             cloud_url = v.UploadToCloud()
             d = v.AsDict()
             self.assertTrue(os.path.exists(file_path))
             self.assertEqual(d['file_id'], fh.id)
             self.assertEqual(d['cloud_url'], cloud_url)
             insert_mock.assert_called_with(
                 trace.cloud_storage.PUBLIC_BUCKET, 'a.html', file_path)
Example #10
0
 def test_from_file(self):
   update_systrace_trace_viewer.update(force_update=True)
   self.assertTrue(os.path.exists(
       update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
   try:
     with tempfile_ext.TemporaryFileName() as output_file_name:
       # use from-file to create a specific expected output
       run_systrace.main_impl(['./run_systrace.py',
                               '--from-file',
                               COMPRESSED_ATRACE_DATA,
                               '-o',
                               output_file_name])
       # and verify file contents
       with contextlib.nested(open(output_file_name, 'r'),
                              open(DECOMPRESSED_ATRACE_DATA, 'r')) as (f1, f2):
         full_trace = f1.read()
         expected_contents = f2.read()
         self.assertTrue(expected_contents in full_trace)
   finally:
     os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
Example #11
0
  def testHtmlOutputGenerationFormatsSingleTrace(self):
    update_systrace_trace_viewer.update(force_update=True)
    self.assertTrue(os.path.exists(
        update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
    with open(ATRACE_DATA) as f:
      atrace_data = f.read().replace(" ", "").strip()
    trace_results = [trace_result.TraceResult('systemTraceEvents', atrace_data)]
    with tempfile_ext.TemporaryFileName() as output_file_name:
      output_generator.GenerateHTMLOutput(trace_results, output_file_name)
      with open(output_file_name, 'r') as f:
        html_output = f.read()
      trace_data = (html_output.split(
        '<script class="trace-data" type="application/text">')[1].split(
        '</script>'))[0].replace(" ", "").strip()

    # Ensure the trace data written in HTML is located within the
    # correct place in the HTML document and that the data is not
    # malformed.
    self.assertEquals(trace_data, atrace_data)
    os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
    def _StartInstance(self):
        """Starts an AVD instance.

    Returns:
      A (Popen, str) 2-tuple that includes the process and serial.
    """
        # Start up the 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,
                '-read-only',
                '-no-window',
            ]
            emulator_env = {}
            if self._emulator_home:
                emulator_env['ANDROID_EMULATOR_HOME'] = self._emulator_home
            sock.listen(1)
            emulator_proc = cmd_helper.Popen(emulator_cmd, env=emulator_env)

            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:
                emulator_serial = timeout_retry.Run(listen_for_serial,
                                                    timeout=30,
                                                    retries=0,
                                                    args=[sock])
            except Exception:
                emulator_proc.terminate()
                raise

            return (emulator_proc, emulator_serial)
Example #13
0
File: avd.py Project: wzis/chromium
  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)
Example #14
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))
Example #15
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.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.
            if snapshot:
                # TODO(crbug.com/922145): Implement support for snapshotting.
                raise NotImplementedError('Snapshotting is not supported yet.')

            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)
Example #16
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)
Example #17
0
    def Create(self,
               force=False,
               snapshot=False,
               keep=False,
               additional_apks=None,
               privileged_apk_tuples=None,
               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, installs additional apks and/or privileged apks, and
       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.
      additional_apks: a list of strings contains the paths to the APKs. These
        APKs will be installed after AVD is started.
      privileged_apk_tuples: a list of (apk_path, device_partition) tuples where
        |apk_path| is a string containing the path to the APK, and
        |device_partition| is a string indicating the system image partition on
        device that contains "priv-app" directory, e.g. "/system", "/product".
      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 = self._avd_home

        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 = self._avd_dir

            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(
                    self._config_ini_path) 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,
                    'hw.mainKeys': 'no',  # Show nav buttons on screen
                })

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

                config_ini_contents['hw.sdCard'] = 'yes'
                if self.avd_settings.sdcard.size:
                    sdcard_path = os.path.join(avd_dir, _SDCARD_NAME)
                    mksdcard_path = os.path.join(
                        os.path.dirname(self._emulator_path), 'mksdcard')
                    cmd_helper.RunCmd([
                        mksdcard_path,
                        self.avd_settings.sdcard.size,
                        sdcard_path,
                    ])
                    config_ini_contents['hw.sdCard.path'] = sdcard_path

            # 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
            # Installing privileged apks requires modifying the system image.
            writable_system = bool(privileged_apk_tuples)
            instance.Start(ensure_system_settings=False,
                           read_only=False,
                           writable_system=writable_system,
                           gpu_mode=_DEFAULT_GPU_MODE,
                           debug_tags=debug_tags)

            assert instance.device is not None, '`instance.device` not initialized.'
            # 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.
            instance.device.WaitUntilFullyBooted(decrypt=True,
                                                 timeout=180,
                                                 retries=0)

            if additional_apks:
                for additional_apk in additional_apks:
                    instance.device.Install(additional_apk,
                                            allow_downgrade=True,
                                            reinstall=True)

            if privileged_apk_tuples:
                system_app.InstallPrivilegedApps(instance.device,
                                                 privileged_apk_tuples)

            # Always disable the network to prevent built-in system apps from
            # updating themselves, which could take over package manager and
            # cause shell command timeout.
            logging.info('Disabling the network.')
            settings.ConfigureContentSettings(
                instance.device, settings.NETWORK_DISABLED_SETTINGS)

            if snapshot:
                # Reboot so that changes like disabling network can take effect.
                instance.device.Reboot()
                instance.SaveSnapshot()

            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:
                        # avd.py is executed with python2.
                        # pylint: disable=W0707
                        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)
Example #18
0
    def Start(self,
              ensure_system_settings=True,
              read_only=True,
              window=False,
              writable_system=False,
              gpu_mode=_DEFAULT_GPU_MODE,
              wipe_data=False,
              debug_tags=None):
        """Starts the emulator running an instance of the given AVD.

    Note when ensure_system_settings is True, the program will wait until the
    emulator is fully booted, and then update system settings.
    """
        is_slow_start = False
        # Force to load system snapshot if detected.
        if self.HasSystemSnapshot():
            if not writable_system:
                logging.info(
                    'System snapshot found. Set "writable_system=True" '
                    'to load it properly.')
                writable_system = True
            if read_only:
                logging.info('System snapshot found. Set "read_only=False" '
                             'to load it properly.')
                read_only = False
        elif writable_system:
            is_slow_start = True
            logging.warning(
                'Emulator will be slow to start, as '
                '"writable_system=True" but system snapshot not found.')

        self._writable_system = writable_system

        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',
                # Explicitly prevent emulator from auto-saving to snapshot on exit.
                '-no-snapshot-save',
                # Explicitly set the snapshot name for auto-load
                '-snapshot',
                self.GetSnapshotName(),
            ]

            if wipe_data:
                emulator_cmd.append('-wipe-data')
            if read_only:
                emulator_cmd.append('-read-only')
            if writable_system:
                emulator_cmd.append('-writable-system')
            # Note when "--gpu-mode" is set to "host":
            #  * It needs a valid DISPLAY env, even if "--emulator-window" is false.
            #    Otherwise it may throw errors like "Failed to initialize backend
            #    EGL display". See the code in https://bit.ly/3ruiMlB as an example
            #    to setup the DISPLAY env with xvfb.
            #  * It will not work under remote sessions like chrome remote desktop.
            if gpu_mode:
                emulator_cmd.extend(['-gpu', gpu_mode])
            if debug_tags:
                emulator_cmd.extend(['-debug', debug_tags])

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

            sock.listen(1)

            logging.info('Starting emulator...')
            logging.info(
                '  With environments: %s',
                ' '.join(['%s=%s' % (k, v) for k, v in emulator_env.items()]))
            logging.info('  With commands: %s', ' '.join(emulator_cmd))

            # TODO(jbudorick): Add support for logging emulator stdout & stderr at
            # higher logging levels.
            # Enable the emulator log when debug_tags is set.
            if not debug_tags:
                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()
                # avd.py is executed with python2.
                # pylint: disable=W0707
                raise AvdException('Emulator failed to start: %s' % str(e))

        # Set the system settings in "Start" here instead of setting in "Create"
        # because "Create" is used during AVD creation, and we want to avoid extra
        # turn-around on rolling AVD.
        if ensure_system_settings:
            assert self.device is not None, '`instance.device` not initialized.'
            self.device.WaitUntilFullyBooted(
                timeout=120 if is_slow_start else 30)
            _EnsureSystemSettings(self.device)
Example #19
0
 def test_enable_with_filename(self):
     with tempfile_ext.TemporaryFileName() as filename:
         trace_enable(filename)
         trace_disable()
         e = ParsedTraceEvents(trace_filename=filename)
         self.assertTrue(len(e) > 0)