# Copyright 2020 - The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """cvd_runtime_config class.""" import json import os import re from acloud import errors _CFG_KEY_CROSVM_BINARY = "crosvm_binary" _CFG_KEY_X_RES = "x_res" _CFG_KEY_Y_RES = "y_res" _CFG_KEY_DPI = "dpi" _CFG_KEY_VIRTUAL_DISK_PATHS = "virtual_disk_paths" _CFG_KEY_INSTANCES = "instances" _CFG_KEY_ADB_IP_PORT = "adb_ip_and_port" _CFG_KEY_INSTANCE_DIR = "instance_dir" _CFG_KEY_VNC_PORT = "vnc_server_port" _CFG_KEY_ADB_PORT = "host_port" _CFG_KEY_ENABLE_WEBRTC = "enable_webrtc" # TODO(148648620): Check instance_home_[id] for backward compatible. _RE_LOCAL_INSTANCE_ID = re.compile(r".+(?:local-instance-|instance_home_)" r"(?P\d+).+") def _GetIdFromInstanceDirStr(instance_dir): """Look for instance id from the path of instance dir. Args: instance_dir: String, path of instance_dir. Returns: String of instance id. """ match = _RE_LOCAL_INSTANCE_ID.match(instance_dir) if match: return match.group("ins_id") # To support the device which is not created by acloud. if os.path.expanduser("~") in instance_dir: return "1" return None class CvdRuntimeConfig(object): """The class that hold the information from cuttlefish_config.json. The example of cuttlefish_config.json { "memory_mb" : 4096, "cpus" : 2, "dpi" : 320, "virtual_disk_paths" : [ "/path-to-image" ], "adb_ip_and_port" : "0.0.0.0:6520", "instance_dir" : "/path-to-instance-dir", } If we launched multiple local instances, the config will be as below: { "memory_mb" : 4096, "cpus" : 2, "dpi" : 320, "instances" : { "1" : { "adb_ip_and_port" : "0.0.0.0:6520", "instance_dir" : "/path-to-instance-dir", "virtual_disk_paths" : [ "/path-to-image" ], } } } If the avd enable the webrtc, the config will be as below: { "enable_webrtc" : true, "vnc_server_binary" : "/home/vsoc-01/bin/vnc_server", "webrtc_assets_dir" : "/home/vsoc-01/usr/share/webrtc/assets", "webrtc_binary" : "/home/vsoc-01/bin/webRTC", "webrtc_certs_dir" : "/home/vsoc-01/usr/share/webrtc/certs", "webrtc_enable_adb_websocket" : false, "webrtc_public_ip" : "0.0.0.0", } """ def __init__(self, config_path=None, raw_data=None): self._config_path = config_path self._instance_id = "1" if raw_data else _GetIdFromInstanceDirStr( config_path) self._config_dict = self._GetCuttlefishRuntimeConfig(config_path, raw_data) self._x_res = self._config_dict.get(_CFG_KEY_X_RES) self._y_res = self._config_dict.get(_CFG_KEY_Y_RES) self._dpi = self._config_dict.get(_CFG_KEY_DPI) crosvm_bin = self._config_dict.get(_CFG_KEY_CROSVM_BINARY) self._cvd_tools_path = (os.path.dirname(crosvm_bin) if crosvm_bin else None) # Below properties will be collected inside of instance id node if there # are more than one instance. self._instance_dir = self._config_dict.get(_CFG_KEY_INSTANCE_DIR) self._vnc_port = self._config_dict.get(_CFG_KEY_VNC_PORT) self._adb_port = self._config_dict.get(_CFG_KEY_ADB_PORT) self._adb_ip_port = self._config_dict.get(_CFG_KEY_ADB_IP_PORT) self._virtual_disk_paths = self._config_dict.get( _CFG_KEY_VIRTUAL_DISK_PATHS) self._enable_webrtc = self._config_dict.get(_CFG_KEY_ENABLE_WEBRTC) if not self._instance_dir: ins_cfg = self._config_dict.get(_CFG_KEY_INSTANCES) ins_dict = ins_cfg.get(self._instance_id) if not ins_dict: raise errors.ConfigError("instances[%s] property does not exist" " in: %s" % (self._instance_id, config_path)) self._instance_dir = ins_dict.get(_CFG_KEY_INSTANCE_DIR) self._vnc_port = ins_dict.get(_CFG_KEY_VNC_PORT) self._adb_port = ins_dict.get(_CFG_KEY_ADB_PORT) self._adb_ip_port = ins_dict.get(_CFG_KEY_ADB_IP_PORT) self._virtual_disk_paths = ins_dict.get(_CFG_KEY_VIRTUAL_DISK_PATHS) @staticmethod def _GetCuttlefishRuntimeConfig(runtime_cf_config_path, raw_data=None): """Get and parse cuttlefish_config.json. Args: runtime_cf_config_path: String, path of the cvd runtime config. raw_data: String, data of the cvd runtime config. Returns: A dictionary that parsed from cuttlefish runtime config. Raises: errors.ConfigError: if file not found or config load failed. """ if raw_data: # if remote instance couldn't fetch the config will return message such as # 'cat: .../cuttlefish_config.json: No such file or directory'. # Add this condition to prevent from JSONDecodeError. try: return json.loads(raw_data) except ValueError as e: raise errors.ConfigError( "An exception happened when loading the raw_data of the " "cvd runtime config:\n%s" % str(e)) if not os.path.exists(runtime_cf_config_path): raise errors.ConfigError( "file does not exist: %s" % runtime_cf_config_path) with open(runtime_cf_config_path, "r") as cf_config: return json.load(cf_config) @property def cvd_tools_path(self): """Return string of the path to the cvd tools.""" return self._cvd_tools_path @property def x_res(self): """Return x_res.""" return self._x_res @property def y_res(self): """Return y_res.""" return self._y_res @property def dpi(self): """Return dpi.""" return self._dpi @property def adb_ip_port(self): """Return adb_ip_port.""" return self._adb_ip_port @property def instance_dir(self): """Return instance_dir.""" return self._instance_dir @property def vnc_port(self): """Return vnc_port.""" return self._vnc_port @property def adb_port(self): """Return adb_port.""" return self._adb_port @property def config_path(self): """Return config_path.""" return self._config_path @property def virtual_disk_paths(self): """Return virtual_disk_paths""" return self._virtual_disk_paths @property def instance_id(self): """Return _instance_id""" return self._instance_id @property def enable_webrtc(self): """Return _enable_webrtc""" return self._enable_webrtc