• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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