def __init__(self, local_instance_id, avd_flavor=None, create_time=None, x_res=None, y_res=None, dpi=None): """Initialize a LocalGoldfishInstance object. Args: local_instance_id: Integer of instance id. avd_flavor: String, the flavor of the virtual device. create_time: String, the creation date and time. x_res: Integer of x dimension. y_res: Integer of y dimension. dpi: Integer of dpi. """ self._id = local_instance_id adb_port = self.console_port + 1 self._adb = AdbTools(adb_port=adb_port, device_serial=self.device_serial) name = self._INSTANCE_NAME_FORMAT % {"id": local_instance_id} elapsed_time = _GetElapsedTime(create_time) if create_time else None fullname = _FULL_NAME_STRING % { "device_serial": self.device_serial, "instance_name": name, "elapsed_time": elapsed_time } if x_res and y_res and dpi: display = _DISPLAY_STRING % { "x_res": x_res, "y_res": y_res, "dpi": dpi } else: display = "unknown" device_information = (self._adb.device_information if self._adb.device_information else None) super(LocalGoldfishInstance, self).__init__(name=name, fullname=fullname, display=display, ip="127.0.0.1", status=None, adb_port=adb_port, avd_type=constants.TYPE_GF, createtime=create_time, elapsed_time=elapsed_time, avd_flavor=avd_flavor, is_local=True, device_information=device_information)
def __init__(self, cf_config_path): """Initialize a localInstance object. Args: cf_config_path: String, path to the cf runtime config. """ self._cf_runtime_cfg = cvd_runtime_config.CvdRuntimeConfig( cf_config_path) self._instance_dir = self._cf_runtime_cfg.instance_dir self._virtual_disk_paths = self._cf_runtime_cfg.virtual_disk_paths self._local_instance_id = int(self._cf_runtime_cfg.instance_id) display = _DISPLAY_STRING % { "x_res": self._cf_runtime_cfg.x_res, "y_res": self._cf_runtime_cfg.y_res, "dpi": self._cf_runtime_cfg.dpi } # TODO(143063678), there's no createtime info in # cuttlefish_config.json so far. name = GetLocalInstanceName(self._local_instance_id) fullname = (_FULL_NAME_STRING % { "device_serial": "127.0.0.1:%s" % self._cf_runtime_cfg.adb_port, "instance_name": name, "elapsed_time": None }) adb_device = AdbTools(self._cf_runtime_cfg.adb_port) device_information = None if adb_device.IsAdbConnected(): device_information = adb_device.device_information super(LocalInstance, self).__init__(name=name, fullname=fullname, display=display, ip="127.0.0.1", status=constants.INS_STATUS_RUNNING, adb_port=self._cf_runtime_cfg.adb_port, vnc_port=self._cf_runtime_cfg.vnc_port, createtime=None, elapsed_time=None, avd_type=constants.TYPE_CF, is_local=True, device_information=device_information, zone=_LOCAL_ZONE)
def GetExistingInstances(cls): """Get the list of instances that adb can send emu commands to.""" instances = [] for serial in AdbTools.GetDeviceSerials(): match = cls._DEVICE_SERIAL_PATTERN.match(serial) if not match: continue port = int(match.group("console_port")) instance_id = (port - cls._EMULATOR_DEFAULT_CONSOLE_PORT) // 2 + 1 instances.append(LocalGoldfishInstance(instance_id)) return instances
def Delete(self): """Execute stop_cvd to stop local cuttlefish instance. - We should get the same host tool used to launch cvd to delete instance , So get stop_cvd bin from the cvd runtime config. - Add CUTTLEFISH_CONFIG_FILE env variable to tell stop_cvd which cvd need to be deleted. - Stop adb since local instance use the fixed adb port and could be reused again soon. """ stop_cvd_cmd = os.path.join(self.cf_runtime_cfg.cvd_tools_path, constants.CMD_STOP_CVD) logger.debug("Running cmd[%s] to delete local cvd", stop_cvd_cmd) with open(os.devnull, "w") as dev_null: cvd_env = os.environ.copy() if self.instance_dir: cvd_env[ constants. ENV_CUTTLEFISH_CONFIG_FILE] = self._cf_runtime_cfg.config_path cvd_env[constants.ENV_CVD_HOME] = GetLocalInstanceHomeDir( self._local_instance_id) cvd_env[constants.ENV_CUTTLEFISH_INSTANCE] = str( self._local_instance_id) else: logger.error( "instance_dir is null!! instance[%d] might not be" " deleted", self._local_instance_id) subprocess.check_call(utils.AddUserGroupsToCmd( stop_cvd_cmd, constants.LIST_CF_USER_GROUPS), stderr=dev_null, stdout=dev_null, shell=True, env=cvd_env) adb_cmd = AdbTools(self.adb_port) # When relaunch a local instance, we need to pass in retry=True to make # sure adb device is completely gone since it will use the same adb port adb_cmd.DisconnectAdb(retry=True)
def CreateGCETypeAVD(cfg, build_target=None, build_id=None, num=1, gce_image=None, local_disk_image=None, cleanup=True, serial_log_file=None, autoconnect=False, report_internal_ip=False, avd_spec=None): """Creates one or multiple gce android devices. Args: cfg: An AcloudConfig instance. build_target: Target name, e.g. "aosp_cf_x86_phone-userdebug" build_id: Build id, a string, e.g. "2263051", "P2804227" num: Number of devices to create. gce_image: string, if given, will use this gce image instead of creating a new one. implies cleanup=False. local_disk_image: string, path to a local disk image, e.g. /tmp/avd-system.tar.gz cleanup: boolean, if True clean up compute engine image and disk image in storage after creating the instance. serial_log_file: A path to a file where serial output should be saved to. autoconnect: Create ssh tunnel(s) and adb connect after device creation. report_internal_ip: Boolean to report the internal ip instead of external ip. avd_spec: AVDSpec object for pass hw_property. Returns: A Report instance. """ r = report.Report(command="create") credentials = auth.CreateCredentials(cfg) compute_client = android_compute_client.AndroidComputeClient( cfg, credentials) try: common_operations.CreateSshKeyPairIfNecessary(cfg) device_pool = AndroidVirtualDevicePool(cfg) device_pool.CreateDevices( num, build_target, build_id, gce_image, local_disk_image, cleanup, extra_data_disk_size_gb=cfg.extra_data_disk_size_gb, precreated_data_image=cfg.precreated_data_image_map.get( cfg.extra_data_disk_size_gb), avd_spec=avd_spec, extra_scopes=cfg.extra_scopes) failures = device_pool.WaitForBoot() # Write result to report. for device in device_pool.devices: ip = (device.ip.internal if report_internal_ip else device.ip.external) device_dict = {"ip": ip, "instance_name": device.instance_name} if autoconnect: forwarded_ports = utils.AutoConnect( ip_addr=ip, rsa_key_file=cfg.ssh_private_key_path, target_vnc_port=constants.GCE_VNC_PORT, target_adb_port=constants.GCE_ADB_PORT, ssh_user=_SSH_USER, client_adb_port=avd_spec.client_adb_port, extra_args_ssh_tunnel=cfg.extra_args_ssh_tunnel) device_dict[constants.VNC_PORT] = forwarded_ports.vnc_port device_dict[constants.ADB_PORT] = forwarded_ports.adb_port if avd_spec.unlock_screen: AdbTools(forwarded_ports.adb_port).AutoUnlockScreen() if device.instance_name in failures: r.AddData(key="devices_failing_boot", value=device_dict) r.AddError(str(failures[device.instance_name])) else: r.AddData(key="devices", value=device_dict) if failures: r.SetStatus(report.Status.BOOT_FAIL) else: r.SetStatus(report.Status.SUCCESS) # Dump serial logs. if serial_log_file: _FetchSerialLogsFromDevices( compute_client, instance_names=[d.instance_name for d in device_pool.devices], port=constants.DEFAULT_SERIAL_PORT, output_file=serial_log_file) except errors.DriverError as e: r.AddError(str(e)) r.SetStatus(report.Status.FAIL) return r
def ReconnectInstance(ssh_private_key_path, instance, reconnect_report, extra_args_ssh_tunnel=None, connect_vnc=True): """Reconnect to the specified instance. It will: - re-establish ssh tunnels for adb/vnc port forwarding - re-establish adb connection - restart vnc client - update device information in reconnect_report Args: ssh_private_key_path: Path to the private key file. e.g. ~/.ssh/acloud_rsa instance: list.Instance() object. reconnect_report: Report object. extra_args_ssh_tunnel: String, extra args for ssh tunnel connection. connect_vnc: Boolean, True will launch vnc. Raises: errors.UnknownAvdType: Unable to reconnect to instance of unknown avd type. """ if instance.avd_type not in utils.AVD_PORT_DICT: raise errors.UnknownAvdType("Unable to reconnect to instance (%s) of " "unknown avd type: %s" % (instance.name, instance.avd_type)) adb_cmd = AdbTools(instance.adb_port) vnc_port = instance.vnc_port adb_port = instance.adb_port # ssh tunnel is up but device is disconnected on adb if instance.ssh_tunnel_is_connected and not adb_cmd.IsAdbConnectionAlive(): adb_cmd.DisconnectAdb() adb_cmd.ConnectAdb() # ssh tunnel is down and it's a remote instance elif not instance.ssh_tunnel_is_connected and not instance.islocal: adb_cmd.DisconnectAdb() forwarded_ports = utils.AutoConnect( ip_addr=instance.ip, rsa_key_file=ssh_private_key_path, target_vnc_port=utils.AVD_PORT_DICT[instance.avd_type].vnc_port, target_adb_port=utils.AVD_PORT_DICT[instance.avd_type].adb_port, ssh_user=constants.GCE_USER, extra_args_ssh_tunnel=extra_args_ssh_tunnel) vnc_port = forwarded_ports.vnc_port adb_port = forwarded_ports.adb_port if _IsWebrtcEnable(instance, constants.GCE_USER, ssh_private_key_path, extra_args_ssh_tunnel): if instance.islocal: if _WebrtcPortOccupied(): raise errors.PortOccupied( "\nReconnect to a local webrtc instance " "is not work because remote webrtc " "instance has established ssh tunnel " "which occupied local webrtc instance " "port. If you want to connect to a " "local-instance of webrtc. please run " "'acloud create --local-instance " "--autoconnect webrtc' directly.") else: utils.EstablishWebRTCSshTunnel( ip_addr=instance.ip, rsa_key_file=ssh_private_key_path, ssh_user=constants.GCE_USER, extra_args_ssh_tunnel=extra_args_ssh_tunnel) utils.LaunchBrowser(constants.WEBRTC_LOCAL_HOST, constants.WEBRTC_LOCAL_PORT) elif (vnc_port and connect_vnc): StartVnc(vnc_port, instance.display) device_dict = { constants.IP: instance.ip, constants.INSTANCE_NAME: instance.name, constants.VNC_PORT: vnc_port, constants.ADB_PORT: adb_port } if vnc_port and adb_port: reconnect_report.AddData(key="devices", value=device_dict) else: # We use 'ps aux' to grep adb/vnc fowarding port from ssh tunnel # command. Therefore we report failure here if no vnc_port and # adb_port found. reconnect_report.AddData(key="device_failing_reconnect", value=device_dict) reconnect_report.AddError(instance.name)
def CreateDevices(command, cfg, device_factory, num, avd_type, report_internal_ip=False, autoconnect=False, serial_log_file=None, client_adb_port=None, boot_timeout_secs=None, unlock_screen=False, wait_for_boot=True, connect_webrtc=False): """Create a set of devices using the given factory. Main jobs in create devices. 1. Create GCE instance: Launch instance in GCP(Google Cloud Platform). 2. Starting up AVD: Wait device boot up. Args: command: The name of the command, used for reporting. cfg: An AcloudConfig instance. device_factory: A factory capable of producing a single device. num: The number of devices to create. avd_type: String, the AVD type(cuttlefish, goldfish...). report_internal_ip: Boolean to report the internal ip instead of external ip. serial_log_file: String, the file path to tar the serial logs. autoconnect: Boolean, whether to auto connect to device. client_adb_port: Integer, Specify port for adb forwarding. boot_timeout_secs: Integer, boot timeout secs. unlock_screen: Boolean, whether to unlock screen after invoke vnc client. wait_for_boot: Boolean, True to check serial log include boot up message. connect_webrtc: Boolean, whether to auto connect webrtc to device. Raises: errors: Create instance fail. Returns: A Report instance. """ reporter = report.Report(command=command) try: CreateSshKeyPairIfNecessary(cfg) device_pool = DevicePool(device_factory) device_pool.CreateDevices(num) device_pool.SetDeviceBuildInfo() if wait_for_boot: failures = device_pool.WaitForBoot(boot_timeout_secs) else: failures = device_factory.GetFailures() if failures: reporter.SetStatus(report.Status.BOOT_FAIL) else: reporter.SetStatus(report.Status.SUCCESS) # Collect logs if serial_log_file: device_pool.CollectSerialPortLogs( serial_log_file, port=constants.DEFAULT_SERIAL_PORT) device_pool.UpdateReport(reporter) # Write result to report. for device in device_pool.devices: ip = (device.ip.internal if report_internal_ip else device.ip.external) device_dict = {"ip": ip, "instance_name": device.instance_name} if device.build_info: device_dict.update(device.build_info) if device.time_info: device_dict.update(device.time_info) if autoconnect: forwarded_ports = utils.AutoConnect( ip_addr=ip, rsa_key_file=cfg.ssh_private_key_path, target_vnc_port=utils.AVD_PORT_DICT[avd_type].vnc_port, target_adb_port=utils.AVD_PORT_DICT[avd_type].adb_port, ssh_user=constants.GCE_USER, client_adb_port=client_adb_port, extra_args_ssh_tunnel=cfg.extra_args_ssh_tunnel) device_dict[constants.VNC_PORT] = forwarded_ports.vnc_port device_dict[constants.ADB_PORT] = forwarded_ports.adb_port if unlock_screen: AdbTools(forwarded_ports.adb_port).AutoUnlockScreen() if connect_webrtc: utils.EstablishWebRTCSshTunnel( ip_addr=ip, rsa_key_file=cfg.ssh_private_key_path, ssh_user=constants.GCE_USER, extra_args_ssh_tunnel=cfg.extra_args_ssh_tunnel) if device.instance_name in failures: device_dict[_ERROR_TYPE] = _DICT_ERROR_TYPE[device.stage] reporter.AddData(key="devices_failing_boot", value=device_dict) reporter.AddError(str(failures[device.instance_name])) else: reporter.AddData(key="devices", value=device_dict) except errors.DriverError as e: reporter.AddError(str(e)) reporter.SetStatus(report.Status.FAIL) return reporter
def __init__(self, gce_instance): """Process the args into class vars. RemoteInstace initialized by gce dict object. We parse the required data from gce_instance to local variables. Reference: https://cloud.google.com/compute/docs/reference/rest/v1/instances/get We also gather more details on client side including the forwarding adb port and vnc port which will be used to determine the status of ssh tunnel connection. The status of gce instance will be displayed in _fullname property: - Connected: If gce instance and ssh tunnel and adb connection are all active. - No connected: If ssh tunnel or adb connection is not found. - Terminated: If we can't retrieve the public ip from gce instance. Args: gce_instance: dict object queried from gce. """ name = gce_instance.get(constants.INS_KEY_NAME) create_time = gce_instance.get(constants.INS_KEY_CREATETIME) elapsed_time = _GetElapsedTime(create_time) status = gce_instance.get(constants.INS_KEY_STATUS) zone = self._GetZoneName(gce_instance.get(constants.INS_KEY_ZONE)) ip = None for network_interface in gce_instance.get("networkInterfaces"): for access_config in network_interface.get("accessConfigs"): ip = access_config.get("natIP") # Get metadata display = None avd_type = None avd_flavor = None for metadata in gce_instance.get("metadata", {}).get("items", []): key = metadata["key"] value = metadata["value"] if key == constants.INS_KEY_DISPLAY: display = value elif key == constants.INS_KEY_AVD_TYPE: avd_type = value elif key == constants.INS_KEY_AVD_FLAVOR: avd_flavor = value # Find ssl tunnel info. adb_port = None vnc_port = None device_information = None if ip: forwarded_ports = self.GetAdbVncPortFromSSHTunnel(ip, avd_type) adb_port = forwarded_ports.adb_port vnc_port = forwarded_ports.vnc_port ssh_tunnel_is_connected = adb_port is not None adb_device = AdbTools(adb_port) if adb_device.IsAdbConnected(): device_information = adb_device.device_information fullname = (_FULL_NAME_STRING % { "device_serial": "127.0.0.1:%d" % adb_port, "instance_name": name, "elapsed_time": elapsed_time }) else: fullname = (_FULL_NAME_STRING % { "device_serial": "not connected", "instance_name": name, "elapsed_time": elapsed_time }) # If instance is terminated, its ip is None. else: ssh_tunnel_is_connected = False fullname = (_FULL_NAME_STRING % { "device_serial": "terminated", "instance_name": name, "elapsed_time": elapsed_time }) super(RemoteInstance, self).__init__(name=name, fullname=fullname, display=display, ip=ip, status=status, adb_port=adb_port, vnc_port=vnc_port, ssh_tunnel_is_connected=ssh_tunnel_is_connected, createtime=create_time, elapsed_time=elapsed_time, avd_type=avd_type, avd_flavor=avd_flavor, is_local=False, device_information=device_information, zone=zone)
def _CreateInstance(self, local_instance_id, local_image_path, host_bins_path, avd_spec, no_prompts): """Create a CVD instance. Args: local_instance_id: Integer of instance id. local_image_path: String of local image directory. host_bins_path: String of host package directory. avd_spec: AVDSpec for the instance. no_prompts: Boolean, True to skip all prompts. Returns: A Report instance. """ if avd_spec.connect_webrtc: utils.ReleasePort(constants.WEBRTC_LOCAL_PORT) launch_cvd_path = os.path.join(host_bins_path, "bin", constants.CMD_LAUNCH_CVD) cmd = self.PrepareLaunchCVDCmd(launch_cvd_path, avd_spec.hw_property, avd_spec.connect_adb, local_image_path, local_instance_id, avd_spec.connect_webrtc, avd_spec.gpu) result_report = report.Report(command="create") instance_name = instance.GetLocalInstanceName(local_instance_id) try: self._LaunchCvd(cmd, local_instance_id, host_bins_path, (avd_spec.boot_timeout_secs or constants.DEFAULT_CF_BOOT_TIMEOUT)) except errors.LaunchCVDFail as launch_error: result_report.SetStatus(report.Status.BOOT_FAIL) result_report.AddDeviceBootFailure(instance_name, constants.LOCALHOST, None, None, error=str(launch_error)) return result_report active_ins = list_instance.GetActiveCVD(local_instance_id) if active_ins: result_report.SetStatus(report.Status.SUCCESS) result_report.AddDevice(instance_name, constants.LOCALHOST, active_ins.adb_port, active_ins.vnc_port) # Launch vnc client if we're auto-connecting. if avd_spec.connect_vnc: utils.LaunchVNCFromReport(result_report, avd_spec, no_prompts) if avd_spec.connect_webrtc: utils.LaunchBrowserFromReport(result_report) if avd_spec.unlock_screen: AdbTools(active_ins.adb_port).AutoUnlockScreen() else: err_msg = "cvd_status return non-zero after launch_cvd" logger.error(err_msg) result_report.SetStatus(report.Status.BOOT_FAIL) result_report.AddDeviceBootFailure(instance_name, constants.LOCALHOST, None, None, error=err_msg) return result_report