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