1# Copyright 2020 - The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""cvd_runtime_config class.""" 15 16import json 17import os 18import re 19 20from acloud import errors 21 22_CFG_KEY_CROSVM_BINARY = "crosvm_binary" 23_CFG_KEY_DISPLAY_CONFIGS = "display_configs" 24_CFG_KEY_VIRTUAL_DISK_PATHS = "virtual_disk_paths" 25_CFG_KEY_INSTANCES = "instances" 26_CFG_KEY_ADB_IP_PORT = "adb_ip_and_port" 27_CFG_KEY_INSTANCE_DIR = "instance_dir" 28_CFG_KEY_ROOT_DIR = "root_dir" 29_CFG_KEY_VNC_PORT = "vnc_server_port" 30# The adb port field name changes from "host_port" to "adb_host_port". 31_CFG_KEY_ADB_PORT = "host_port" 32_CFG_KEY_ADB_HOST_PORT = "adb_host_port" 33_CFG_KEY_FASTBOOT_HOST_PORT = "fastboot_host_port" 34_CFG_KEY_ENABLE_WEBRTC = "enable_webrtc" 35# TODO(148648620): Check instance_home_[id] for backward compatible. 36_RE_LOCAL_INSTANCE_ID = re.compile(r".+(?:local-instance-|instance_home_)" 37 r"(?P<ins_id>\d+).+") 38 39 40def _GetIdFromInstanceDirStr(instance_dir): 41 """Look for instance id from the path of instance dir. 42 43 Args: 44 instance_dir: String, path of instance_dir. 45 46 Returns: 47 String of instance id. 48 """ 49 match = _RE_LOCAL_INSTANCE_ID.match(instance_dir) 50 if match: 51 return match.group("ins_id") 52 53 # To support the device which is not created by acloud. 54 if os.path.expanduser("~") in instance_dir: 55 return "1" 56 57 return None 58 59 60class CvdRuntimeConfig(): 61 """The class that hold the information from cuttlefish_config.json. 62 63 The example of cuttlefish_config.json 64 { 65 "memory_mb" : 4096, 66 "cpus" : 2, 67 "display_configs" : 68 [ 69 { 70 "dpi" : 160, 71 "x_res" : 1280, 72 "y_res" : 700 73 } 74 ], 75 "dpi" : 320, 76 "virtual_disk_paths" : 77 [ 78 "/path-to-image" 79 ], 80 "adb_ip_and_port" : "0.0.0.0:6520", 81 "instance_dir" : "/path-to-instance-dir", 82 } 83 84 If we launched multiple local instances, the config will be as below: 85 { 86 "memory_mb" : 4096, 87 "cpus" : 2, 88 "dpi" : 320, 89 "instances" : 90 { 91 "1" : 92 { 93 "adb_ip_and_port" : "0.0.0.0:6520", 94 "instance_dir" : "/path-to-instance-dir", 95 "webrtc_device_id" : "cvd-1", 96 "virtual_disk_paths" : 97 [ 98 "/path-to-image" 99 ], 100 } 101 } 102 } 103 104 If the avd enable the webrtc, the config will be as below: 105 { 106 "enable_webrtc" : true, 107 "vnc_server_binary" : "/home/vsoc-01/bin/vnc_server", 108 "webrtc_assets_dir" : "/home/vsoc-01/usr/share/webrtc/assets", 109 "webrtc_binary" : "/home/vsoc-01/bin/webRTC", 110 "webrtc_certs_dir" : "/home/vsoc-01/usr/share/webrtc/certs", 111 "webrtc_public_ip" : "0.0.0.0", 112 } 113 114 """ 115 116 def __init__(self, config_path=None, raw_data=None): 117 if not config_path and not raw_data: 118 raise errors.ConfigError("No cuttlefish config found!") 119 self._config_path = config_path 120 self._instance_id = "1" if raw_data else _GetIdFromInstanceDirStr( 121 config_path) 122 self._config_dict = self._GetCuttlefishRuntimeConfig(config_path, 123 raw_data) 124 self._instances = self._config_dict.get(_CFG_KEY_INSTANCES) 125 # Old runtime config doesn't have "instances" information. 126 self._instance_ids = list(self._instances.keys()) if self._instances else ["1"] 127 self._display_configs = self._config_dict.get(_CFG_KEY_DISPLAY_CONFIGS, {}) 128 self._root_dir = self._config_dict.get(_CFG_KEY_ROOT_DIR) 129 crosvm_bin = self._config_dict.get(_CFG_KEY_CROSVM_BINARY) 130 self._cvd_tools_path = (os.path.dirname(crosvm_bin) 131 if crosvm_bin else None) 132 133 # Below properties will be collected inside of instance id node if there 134 # are more than one instance. 135 self._instance_dir = self._config_dict.get(_CFG_KEY_INSTANCE_DIR) 136 self._vnc_port = self._config_dict.get(_CFG_KEY_VNC_PORT) 137 self._adb_port = (self._config_dict.get(_CFG_KEY_ADB_PORT) or 138 self._config_dict.get(_CFG_KEY_ADB_HOST_PORT)) 139 self._adb_ip_port = self._config_dict.get(_CFG_KEY_ADB_IP_PORT) 140 self._virtual_disk_paths = self._config_dict.get( 141 _CFG_KEY_VIRTUAL_DISK_PATHS) 142 self._enable_webrtc = self._config_dict.get(_CFG_KEY_ENABLE_WEBRTC) 143 if not self._instance_dir: 144 ins_dict = self._instances.get(self._instance_id) 145 if not ins_dict: 146 raise errors.ConfigError("instances[%s] property does not exist" 147 " in: %s" % 148 (self._instance_id, config_path)) 149 self._instance_dir = ins_dict.get(_CFG_KEY_INSTANCE_DIR) 150 self._vnc_port = ins_dict.get(_CFG_KEY_VNC_PORT) 151 self._adb_port = (ins_dict.get(_CFG_KEY_ADB_PORT) or 152 ins_dict.get(_CFG_KEY_ADB_HOST_PORT)) 153 self._adb_ip_port = ins_dict.get(_CFG_KEY_ADB_IP_PORT) 154 self._fastboot_port = ins_dict.get(_CFG_KEY_FASTBOOT_HOST_PORT) 155 self._virtual_disk_paths = ins_dict.get(_CFG_KEY_VIRTUAL_DISK_PATHS) 156 if not self._cvd_tools_path: 157 self._cvd_tools_path = os.path.dirname( 158 ins_dict.get(_CFG_KEY_CROSVM_BINARY)) 159 160 @staticmethod 161 def _GetCuttlefishRuntimeConfig(runtime_cf_config_path, raw_data=None): 162 """Get and parse cuttlefish_config.json. 163 164 Args: 165 runtime_cf_config_path: String, path of the cvd runtime config. 166 raw_data: String, data of the cvd runtime config. 167 168 Returns: 169 A dictionary that parsed from cuttlefish runtime config. 170 171 Raises: 172 errors.ConfigError: if file not found or config load failed. 173 """ 174 if raw_data: 175 # if remote instance couldn't fetch the config will return message such as 176 # 'cat: .../cuttlefish_config.json: No such file or directory'. 177 # Add this condition to prevent from JSONDecodeError. 178 try: 179 return json.loads(raw_data) 180 except ValueError as e: 181 raise errors.ConfigError( 182 "An exception happened when loading the raw_data of the " 183 "cvd runtime config:\n%s" % str(e)) 184 if not os.path.exists(runtime_cf_config_path): 185 raise errors.ConfigError( 186 "file does not exist: %s" % runtime_cf_config_path) 187 with open(runtime_cf_config_path, "r") as cf_config: 188 return json.load(cf_config) 189 190 @property 191 def cvd_tools_path(self): 192 """Return string of the path to the cvd tools.""" 193 return self._cvd_tools_path 194 195 @property 196 def display_configs(self): 197 """Return display_configs.""" 198 return self._display_configs 199 200 @property 201 def adb_ip_port(self): 202 """Return adb_ip_port.""" 203 return self._adb_ip_port 204 205 @property 206 def instance_dir(self): 207 """Return instance_dir.""" 208 return self._instance_dir 209 210 @property 211 def root_dir(self): 212 """Return root_dir.""" 213 return self._root_dir 214 215 @property 216 def vnc_port(self): 217 """Return vnc_port.""" 218 return self._vnc_port 219 220 @property 221 def adb_port(self): 222 """Return adb_port.""" 223 return self._adb_port 224 225 @property 226 def fastboot_port(self): 227 """Return fastboot_port""" 228 return self._fastboot_port 229 230 @property 231 def config_path(self): 232 """Return config_path.""" 233 return self._config_path 234 235 @property 236 def virtual_disk_paths(self): 237 """Return virtual_disk_paths""" 238 return self._virtual_disk_paths 239 240 @property 241 def instance_id(self): 242 """Return _instance_id""" 243 return self._instance_id 244 245 @property 246 def instance_ids(self): 247 """Return _instance_ids""" 248 return self._instance_ids 249 250 @property 251 def instances(self): 252 """Return _instances""" 253 return self._instances 254 255 @property 256 def enable_webrtc(self): 257 """Return _enable_webrtc""" 258 return self._enable_webrtc 259