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_ADB_CONNECTOR_BINARY = "adb_connector_binary" 23_CFG_KEY_X_RES = "x_res" 24_CFG_KEY_Y_RES = "y_res" 25_CFG_KEY_DPI = "dpi" 26_CFG_KEY_VIRTUAL_DISK_PATHS = "virtual_disk_paths" 27_CFG_KEY_INSTANCES = "instances" 28_CFG_KEY_ADB_IP_PORT = "adb_ip_and_port" 29_CFG_KEY_INSTANCE_DIR = "instance_dir" 30_CFG_KEY_VNC_PORT = "vnc_server_port" 31_CFG_KEY_ADB_PORT = "host_port" 32_CFG_KEY_ENABLE_WEBRTC = "enable_webrtc" 33# TODO(148648620): Check instance_home_[id] for backward compatible. 34_RE_LOCAL_INSTANCE_ID = re.compile(r".+(?:local-instance-|instance_home_)" 35 r"(?P<ins_id>\d+).+") 36 37 38def _GetIdFromInstanceDirStr(instance_dir): 39 """Look for instance id from the path of instance dir. 40 41 Args: 42 instance_dir: String, path of instance_dir. 43 44 Returns: 45 String of instance id. 46 """ 47 match = _RE_LOCAL_INSTANCE_ID.match(instance_dir) 48 if match: 49 return match.group("ins_id") 50 else: 51 # To support the device which is not created by acloud. 52 if os.path.expanduser("~") in instance_dir: 53 return "1" 54 55 return None 56 57 58class CvdRuntimeConfig(object): 59 """The class that hold the information from cuttlefish_config.json. 60 61 The example of cuttlefish_config.json 62 { 63 "memory_mb" : 4096, 64 "cpus" : 2, 65 "dpi" : 320, 66 "virtual_disk_paths" : 67 [ 68 "/path-to-image" 69 ], 70 "adb_ip_and_port" : "127.0.0.1:6520", 71 "instance_dir" : "/path-to-instance-dir", 72 } 73 74 If we launched multiple local instances, the config will be as below: 75 { 76 "memory_mb" : 4096, 77 "cpus" : 2, 78 "dpi" : 320, 79 "instances" : 80 { 81 "1" : 82 { 83 "adb_ip_and_port" : "127.0.0.1:6520", 84 "instance_dir" : "/path-to-instance-dir", 85 "virtual_disk_paths" : 86 [ 87 "/path-to-image" 88 ], 89 } 90 } 91 } 92 93 If the avd enable the webrtc, the config will be as below: 94 { 95 "enable_webrtc" : true, 96 "vnc_server_binary" : "/home/vsoc-01/bin/vnc_server", 97 "webrtc_assets_dir" : "/home/vsoc-01/usr/share/webrtc/assets", 98 "webrtc_binary" : "/home/vsoc-01/bin/webRTC", 99 "webrtc_certs_dir" : "/home/vsoc-01/usr/share/webrtc/certs", 100 "webrtc_enable_adb_websocket" : false, 101 "webrtc_public_ip" : "127.0.0.1", 102 } 103 104 """ 105 106 def __init__(self, config_path=None, raw_data=None): 107 self._config_path = config_path 108 self._instance_id = "1" if raw_data else _GetIdFromInstanceDirStr( 109 config_path) 110 self._config_dict = self._GetCuttlefishRuntimeConfig(config_path, 111 raw_data) 112 self._x_res = self._config_dict.get(_CFG_KEY_X_RES) 113 self._y_res = self._config_dict.get(_CFG_KEY_Y_RES) 114 self._dpi = self._config_dict.get(_CFG_KEY_DPI) 115 adb_connector = self._config_dict.get(_CFG_KEY_ADB_CONNECTOR_BINARY) 116 self._cvd_tools_path = (os.path.dirname(adb_connector) 117 if adb_connector else None) 118 119 # Below properties will be collected inside of instance id node if there 120 # are more than one instance. 121 self._instance_dir = self._config_dict.get(_CFG_KEY_INSTANCE_DIR) 122 self._vnc_port = self._config_dict.get(_CFG_KEY_VNC_PORT) 123 self._adb_port = self._config_dict.get(_CFG_KEY_ADB_PORT) 124 self._adb_ip_port = self._config_dict.get(_CFG_KEY_ADB_IP_PORT) 125 self._virtual_disk_paths = self._config_dict.get( 126 _CFG_KEY_VIRTUAL_DISK_PATHS) 127 self._enable_webrtc = self._config_dict.get(_CFG_KEY_ENABLE_WEBRTC) 128 if not self._instance_dir: 129 ins_cfg = self._config_dict.get(_CFG_KEY_INSTANCES) 130 ins_dict = ins_cfg.get(self._instance_id) 131 if not ins_dict: 132 raise errors.ConfigError("instances[%s] property does not exist" 133 " in: %s" % 134 (self._instance_id, config_path)) 135 self._instance_dir = ins_dict.get(_CFG_KEY_INSTANCE_DIR) 136 self._vnc_port = ins_dict.get(_CFG_KEY_VNC_PORT) 137 self._adb_port = ins_dict.get(_CFG_KEY_ADB_PORT) 138 self._adb_ip_port = ins_dict.get(_CFG_KEY_ADB_IP_PORT) 139 self._virtual_disk_paths = ins_dict.get(_CFG_KEY_VIRTUAL_DISK_PATHS) 140 141 @staticmethod 142 def _GetCuttlefishRuntimeConfig(runtime_cf_config_path, raw_data=None): 143 """Get and parse cuttlefish_config.json. 144 145 Args: 146 runtime_cf_config_path: String, path of the cvd runtime config. 147 raw_data: String, data of the cvd runtime config. 148 149 Returns: 150 A dictionary that parsed from cuttlefish runtime config. 151 152 Raises: 153 errors.ConfigError: if file not found or config load failed. 154 """ 155 if raw_data: 156 # if remote instance couldn't fetch the config will return message such as 157 # 'cat: .../cuttlefish_config.json: No such file or directory'. 158 # Add this condition to prevent from JSONDecodeError. 159 try: 160 return json.loads(raw_data) 161 except ValueError as e: 162 raise errors.ConfigError( 163 "An exception happened when loading the raw_data of the " 164 "cvd runtime config:\n%s" % str(e)) 165 if not os.path.exists(runtime_cf_config_path): 166 raise errors.ConfigError( 167 "file does not exist: %s" % runtime_cf_config_path) 168 with open(runtime_cf_config_path, "r") as cf_config: 169 return json.load(cf_config) 170 171 @property 172 def cvd_tools_path(self): 173 """Return string of the path to the cvd tools.""" 174 return self._cvd_tools_path 175 176 @property 177 def x_res(self): 178 """Return x_res.""" 179 return self._x_res 180 181 @property 182 def y_res(self): 183 """Return y_res.""" 184 return self._y_res 185 186 @property 187 def dpi(self): 188 """Return dpi.""" 189 return self._dpi 190 191 @property 192 def adb_ip_port(self): 193 """Return adb_ip_port.""" 194 return self._adb_ip_port 195 196 @property 197 def instance_dir(self): 198 """Return instance_dir.""" 199 return self._instance_dir 200 201 @property 202 def vnc_port(self): 203 """Return vnc_port.""" 204 return self._vnc_port 205 206 @property 207 def adb_port(self): 208 """Return adb_port.""" 209 return self._adb_port 210 211 @property 212 def config_path(self): 213 """Return config_path.""" 214 return self._config_path 215 216 @property 217 def virtual_disk_paths(self): 218 """Return virtual_disk_paths""" 219 return self._virtual_disk_paths 220 221 @property 222 def instance_id(self): 223 """Return _instance_id""" 224 return self._instance_id 225 226 @property 227 def enable_webrtc(self): 228 """Return _enable_webrtc""" 229 return self._enable_webrtc 230