1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/libs/config/cuttlefish_config.h"
18
19 #include <algorithm>
20 #include <climits>
21 #include <cstdint>
22 #include <cstdlib>
23 #include <cstring>
24 #include <fstream>
25 #include <iomanip>
26 #include <iterator>
27 #include <sstream>
28 #include <string>
29 #include <time.h>
30
31 #include <android-base/strings.h>
32 #include <android-base/logging.h>
33 #include <json/json.h>
34
35 #include "common/libs/utils/environment.h"
36 #include "common/libs/utils/files.h"
37 #include "host/libs/vm_manager/crosvm_manager.h"
38 #include "host/libs/vm_manager/gem5_manager.h"
39 #include "host/libs/vm_manager/qemu_manager.h"
40
41 namespace cuttlefish {
42 namespace {
43
44 static constexpr int kDefaultInstance = 1;
45
InstanceFromString(std::string instance_str)46 int InstanceFromString(std::string instance_str) {
47 if (android::base::StartsWith(instance_str, kVsocUserPrefix)) {
48 instance_str = instance_str.substr(std::string(kVsocUserPrefix).size());
49 } else if (android::base::StartsWith(instance_str, kCvdNamePrefix)) {
50 instance_str = instance_str.substr(std::string(kCvdNamePrefix).size());
51 }
52
53 int instance = std::stoi(instance_str);
54 if (instance <= 0) {
55 LOG(INFO) << "Failed to interpret \"" << instance_str << "\" as an id, "
56 << "using instance id " << kDefaultInstance;
57 return kDefaultInstance;
58 }
59 return instance;
60 }
61
InstanceFromEnvironment()62 int InstanceFromEnvironment() {
63 std::string instance_str = StringFromEnv(kCuttlefishInstanceEnvVarName, "");
64 if (instance_str.empty()) {
65 // Try to get it from the user instead
66 instance_str = StringFromEnv("USER", "");
67
68 if (instance_str.empty()) {
69 LOG(DEBUG) << kCuttlefishInstanceEnvVarName
70 << " and USER unset, using instance id " << kDefaultInstance;
71 return kDefaultInstance;
72 }
73 if (!android::base::StartsWith(instance_str, kVsocUserPrefix)) {
74 // No user or we don't recognize this user
75 LOG(DEBUG) << "Non-vsoc user, using instance id " << kDefaultInstance;
76 return kDefaultInstance;
77 }
78 }
79 return InstanceFromString(instance_str);
80 }
81
82 const char* kInstances = "instances";
83
84
85 } // namespace
86
87 const char* const kGpuModeAuto = "auto";
88 const char* const kGpuModeDrmVirgl = "drm_virgl";
89 const char* const kGpuModeGfxstream = "gfxstream";
90 const char* const kGpuModeGfxstreamGuestAngle = "gfxstream_guest_angle";
91 const char* const kGpuModeGuestSwiftshader = "guest_swiftshader";
92 const char* const kGpuModeNone = "none";
93
94 const char* const kHwComposerAuto = "auto";
95 const char* const kHwComposerDrm = "drm";
96 const char* const kHwComposerRanchu = "ranchu";
97 const char* const kHwComposerNone = "none";
98
DefaultEnvironmentPath(const char * environment_key,const char * default_value,const char * subpath)99 std::string DefaultEnvironmentPath(const char* environment_key,
100 const char* default_value,
101 const char* subpath) {
102 return StringFromEnv(environment_key, default_value) + "/" + subpath;
103 }
104
105 ConfigFragment::~ConfigFragment() = default;
106
107 static constexpr char kFragments[] = "fragments";
LoadFragment(ConfigFragment & fragment) const108 bool CuttlefishConfig::LoadFragment(ConfigFragment& fragment) const {
109 if (!dictionary_->isMember(kFragments)) {
110 LOG(ERROR) << "Fragments member was missing";
111 return false;
112 }
113 const Json::Value& json_fragments = (*dictionary_)[kFragments];
114 if (!json_fragments.isMember(fragment.Name())) {
115 LOG(ERROR) << "Could not find a fragment called " << fragment.Name();
116 return false;
117 }
118 return fragment.Deserialize(json_fragments[fragment.Name()]);
119 }
SaveFragment(const ConfigFragment & fragment)120 bool CuttlefishConfig::SaveFragment(const ConfigFragment& fragment) {
121 Json::Value& json_fragments = (*dictionary_)[kFragments];
122 if (json_fragments.isMember(fragment.Name())) {
123 LOG(ERROR) << "Already have a fragment called " << fragment.Name();
124 return false;
125 }
126 json_fragments[fragment.Name()] = fragment.Serialize();
127 return true;
128 }
129
130 static constexpr char kRootDir[] = "root_dir";
root_dir() const131 std::string CuttlefishConfig::root_dir() const {
132 return (*dictionary_)[kRootDir].asString();
133 }
set_root_dir(const std::string & root_dir)134 void CuttlefishConfig::set_root_dir(const std::string& root_dir) {
135 (*dictionary_)[kRootDir] = root_dir;
136 }
137
138 static constexpr char kVmManager[] = "vm_manager";
vm_manager() const139 std::string CuttlefishConfig::vm_manager() const {
140 return (*dictionary_)[kVmManager].asString();
141 }
set_vm_manager(const std::string & name)142 void CuttlefishConfig::set_vm_manager(const std::string& name) {
143 (*dictionary_)[kVmManager] = name;
144 }
145
StringToSecureHal(std::string mode)146 static SecureHal StringToSecureHal(std::string mode) {
147 std::transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
148 if (mode == "keymint") {
149 return SecureHal::Keymint;
150 } else if (mode == "gatekeeper") {
151 return SecureHal::Gatekeeper;
152 } else if (mode == "oemlock") {
153 return SecureHal::Oemlock;
154 } else {
155 return SecureHal::Unknown;
156 }
157 }
158
159 static constexpr char kSecureHals[] = "secure_hals";
secure_hals() const160 std::set<SecureHal> CuttlefishConfig::secure_hals() const {
161 std::set<SecureHal> args_set;
162 for (auto& hal : (*dictionary_)[kSecureHals]) {
163 args_set.insert(StringToSecureHal(hal.asString()));
164 }
165 return args_set;
166 }
set_secure_hals(const std::set<std::string> & hals)167 void CuttlefishConfig::set_secure_hals(const std::set<std::string>& hals) {
168 Json::Value hals_json_obj(Json::arrayValue);
169 for (const auto& hal : hals) {
170 hals_json_obj.append(hal);
171 }
172 (*dictionary_)[kSecureHals] = hals_json_obj;
173 }
174
175 static constexpr char kCrosvmBinary[] = "crosvm_binary";
crosvm_binary() const176 std::string CuttlefishConfig::crosvm_binary() const {
177 return (*dictionary_)[kCrosvmBinary].asString();
178 }
set_crosvm_binary(const std::string & crosvm_binary)179 void CuttlefishConfig::set_crosvm_binary(const std::string& crosvm_binary) {
180 (*dictionary_)[kCrosvmBinary] = crosvm_binary;
181 }
182
183 static constexpr char kGem5DebugFlags[] = "gem5_debug_flags";
gem5_debug_flags() const184 std::string CuttlefishConfig::gem5_debug_flags() const {
185 return (*dictionary_)[kGem5DebugFlags].asString();
186 }
set_gem5_debug_flags(const std::string & gem5_debug_flags)187 void CuttlefishConfig::set_gem5_debug_flags(const std::string& gem5_debug_flags) {
188 (*dictionary_)[kGem5DebugFlags] = gem5_debug_flags;
189 }
190
191 static constexpr char kWebRTCCertsDir[] = "webrtc_certs_dir";
set_webrtc_certs_dir(const std::string & certs_dir)192 void CuttlefishConfig::set_webrtc_certs_dir(const std::string& certs_dir) {
193 (*dictionary_)[kWebRTCCertsDir] = certs_dir;
194 }
webrtc_certs_dir() const195 std::string CuttlefishConfig::webrtc_certs_dir() const {
196 return (*dictionary_)[kWebRTCCertsDir].asString();
197 }
198
199 static constexpr char kSigServerPort[] = "webrtc_sig_server_port";
set_sig_server_port(int port)200 void CuttlefishConfig::set_sig_server_port(int port) {
201 (*dictionary_)[kSigServerPort] = port;
202 }
sig_server_port() const203 int CuttlefishConfig::sig_server_port() const {
204 return (*dictionary_)[kSigServerPort].asInt();
205 }
206
207 static constexpr char kSigServerAddress[] = "webrtc_sig_server_addr";
set_sig_server_address(const std::string & addr)208 void CuttlefishConfig::set_sig_server_address(const std::string& addr) {
209 (*dictionary_)[kSigServerAddress] = addr;
210 }
sig_server_address() const211 std::string CuttlefishConfig::sig_server_address() const {
212 return (*dictionary_)[kSigServerAddress].asString();
213 }
214
215 static constexpr char kSigServerPath[] = "webrtc_sig_server_path";
set_sig_server_path(const std::string & path)216 void CuttlefishConfig::set_sig_server_path(const std::string& path) {
217 // Don't use SetPath here, it's a URL path not a file system path
218 (*dictionary_)[kSigServerPath] = path;
219 }
sig_server_path() const220 std::string CuttlefishConfig::sig_server_path() const {
221 return (*dictionary_)[kSigServerPath].asString();
222 }
223
224 static constexpr char kSigServerSecure[] = "webrtc_sig_server_secure";
set_sig_server_secure(bool secure)225 void CuttlefishConfig::set_sig_server_secure(bool secure) {
226 (*dictionary_)[kSigServerSecure] = secure;
227 }
sig_server_secure() const228 bool CuttlefishConfig::sig_server_secure() const {
229 return (*dictionary_)[kSigServerSecure].asBool();
230 }
231
232 static constexpr char kSigServerStrict[] = "webrtc_sig_server_strict";
set_sig_server_strict(bool strict)233 void CuttlefishConfig::set_sig_server_strict(bool strict) {
234 (*dictionary_)[kSigServerStrict] = strict;
235 }
sig_server_strict() const236 bool CuttlefishConfig::sig_server_strict() const {
237 return (*dictionary_)[kSigServerStrict].asBool();
238 }
239
240 static constexpr char kHostToolsVersion[] = "host_tools_version";
set_host_tools_version(const std::map<std::string,uint32_t> & versions)241 void CuttlefishConfig::set_host_tools_version(
242 const std::map<std::string, uint32_t>& versions) {
243 Json::Value json(Json::objectValue);
244 for (const auto& [key, value] : versions) {
245 json[key] = value;
246 }
247 (*dictionary_)[kHostToolsVersion] = json;
248 }
host_tools_version() const249 std::map<std::string, uint32_t> CuttlefishConfig::host_tools_version() const {
250 if (!dictionary_->isMember(kHostToolsVersion)) {
251 return {};
252 }
253 std::map<std::string, uint32_t> versions;
254 const auto& elem = (*dictionary_)[kHostToolsVersion];
255 for (auto it = elem.begin(); it != elem.end(); it++) {
256 versions[it.key().asString()] = it->asUInt();
257 }
258 return versions;
259 }
260
261 static constexpr char kenableHostUwb[] = "enable_host_uwb";
set_enable_host_uwb(bool enable_host_uwb)262 void CuttlefishConfig::set_enable_host_uwb(bool enable_host_uwb) {
263 (*dictionary_)[kenableHostUwb] = enable_host_uwb;
264 }
enable_host_uwb() const265 bool CuttlefishConfig::enable_host_uwb() const {
266 return (*dictionary_)[kenableHostUwb].asBool();
267 }
268
269 static constexpr char kenableHostUwbConnector[] = "enable_host_uwb_connector";
set_enable_host_uwb_connector(bool enable_host_uwb)270 void CuttlefishConfig::set_enable_host_uwb_connector(bool enable_host_uwb) {
271 (*dictionary_)[kenableHostUwbConnector] = enable_host_uwb;
272 }
enable_host_uwb_connector() const273 bool CuttlefishConfig::enable_host_uwb_connector() const {
274 return (*dictionary_)[kenableHostUwbConnector].asBool();
275 }
276
277 static constexpr char kPicaUciPort[] = "pica_uci_port";
pica_uci_port() const278 int CuttlefishConfig::pica_uci_port() const {
279 return (*dictionary_)[kPicaUciPort].asInt();
280 }
set_pica_uci_port(int pica_uci_port)281 void CuttlefishConfig::set_pica_uci_port(int pica_uci_port) {
282 (*dictionary_)[kPicaUciPort] = pica_uci_port;
283 }
284
285 static constexpr char kenableHostBluetooth[] = "enable_host_bluetooth";
set_enable_host_bluetooth(bool enable_host_bluetooth)286 void CuttlefishConfig::set_enable_host_bluetooth(bool enable_host_bluetooth) {
287 (*dictionary_)[kenableHostBluetooth] = enable_host_bluetooth;
288 }
enable_host_bluetooth() const289 bool CuttlefishConfig::enable_host_bluetooth() const {
290 return (*dictionary_)[kenableHostBluetooth].asBool();
291 }
292
293 static constexpr char kenableHostBluetoothConnector[] = "enable_host_bluetooth_connector";
set_enable_host_bluetooth_connector(bool enable_host_bluetooth)294 void CuttlefishConfig::set_enable_host_bluetooth_connector(bool enable_host_bluetooth) {
295 (*dictionary_)[kenableHostBluetoothConnector] = enable_host_bluetooth;
296 }
enable_host_bluetooth_connector() const297 bool CuttlefishConfig::enable_host_bluetooth_connector() const {
298 return (*dictionary_)[kenableHostBluetoothConnector].asBool();
299 }
300
301 static constexpr char kNetsimRadios[] = "netsim_radios";
302
netsim_radio_enable(NetsimRadio flag)303 void CuttlefishConfig::netsim_radio_enable(NetsimRadio flag) {
304 if (dictionary_->isMember(kNetsimRadios)) {
305 // OR the radio to current set of radios
306 (*dictionary_)[kNetsimRadios] = (*dictionary_)[kNetsimRadios].asInt() | flag;
307 } else {
308 (*dictionary_)[kNetsimRadios] = flag;
309 }
310 }
311
netsim_radio_enabled(NetsimRadio flag) const312 bool CuttlefishConfig::netsim_radio_enabled(NetsimRadio flag) const {
313 return (*dictionary_)[kNetsimRadios].asInt() & flag;
314 }
315
316 static constexpr char kEnableMetrics[] = "enable_metrics";
set_enable_metrics(std::string enable_metrics)317 void CuttlefishConfig::set_enable_metrics(std::string enable_metrics) {
318 (*dictionary_)[kEnableMetrics] = kUnknown;
319 if (!enable_metrics.empty()) {
320 switch (enable_metrics.at(0)) {
321 case 'y':
322 case 'Y':
323 (*dictionary_)[kEnableMetrics] = kYes;
324 break;
325 case 'n':
326 case 'N':
327 (*dictionary_)[kEnableMetrics] = kNo;
328 break;
329 }
330 }
331 }
enable_metrics() const332 CuttlefishConfig::Answer CuttlefishConfig::enable_metrics() const {
333 return (CuttlefishConfig::Answer)(*dictionary_)[kEnableMetrics].asInt();
334 }
335
336 static constexpr char kMetricsBinary[] = "metrics_binary";
set_metrics_binary(const std::string & metrics_binary)337 void CuttlefishConfig::set_metrics_binary(const std::string& metrics_binary) {
338 (*dictionary_)[kMetricsBinary] = metrics_binary;
339 }
metrics_binary() const340 std::string CuttlefishConfig::metrics_binary() const {
341 return (*dictionary_)[kMetricsBinary].asString();
342 }
343
344 static constexpr char kExtraKernelCmdline[] = "extra_kernel_cmdline";
set_extra_kernel_cmdline(const std::string & extra_cmdline)345 void CuttlefishConfig::set_extra_kernel_cmdline(
346 const std::string& extra_cmdline) {
347 Json::Value args_json_obj(Json::arrayValue);
348 for (const auto& arg : android::base::Split(extra_cmdline, " ")) {
349 args_json_obj.append(arg);
350 }
351 (*dictionary_)[kExtraKernelCmdline] = args_json_obj;
352 }
extra_kernel_cmdline() const353 std::vector<std::string> CuttlefishConfig::extra_kernel_cmdline() const {
354 std::vector<std::string> cmdline;
355 for (const Json::Value& arg : (*dictionary_)[kExtraKernelCmdline]) {
356 cmdline.push_back(arg.asString());
357 }
358 return cmdline;
359 }
360
361 static constexpr char kExtraBootconfigArgs[] = "extra_bootconfig_args";
set_extra_bootconfig_args(const std::string & extra_bootconfig_args)362 void CuttlefishConfig::set_extra_bootconfig_args(
363 const std::string& extra_bootconfig_args) {
364 Json::Value args_json_obj(Json::arrayValue);
365 for (const auto& arg : android::base::Split(extra_bootconfig_args, " ")) {
366 args_json_obj.append(arg);
367 }
368 (*dictionary_)[kExtraBootconfigArgs] = args_json_obj;
369 }
extra_bootconfig_args() const370 std::vector<std::string> CuttlefishConfig::extra_bootconfig_args() const {
371 std::vector<std::string> bootconfig;
372 for (const Json::Value& arg : (*dictionary_)[kExtraBootconfigArgs]) {
373 bootconfig.push_back(arg.asString());
374 }
375 return bootconfig;
376 }
377
378 static constexpr char kVirtioMac80211Hwsim[] = "virtio_mac80211_hwsim";
set_virtio_mac80211_hwsim(bool virtio_mac80211_hwsim)379 void CuttlefishConfig::set_virtio_mac80211_hwsim(bool virtio_mac80211_hwsim) {
380 (*dictionary_)[kVirtioMac80211Hwsim] = virtio_mac80211_hwsim;
381 }
virtio_mac80211_hwsim() const382 bool CuttlefishConfig::virtio_mac80211_hwsim() const {
383 return (*dictionary_)[kVirtioMac80211Hwsim].asBool();
384 }
385
386 static constexpr char kVhostUserMac80211Hwsim[] = "vhost_user_mac80211_hwsim";
set_vhost_user_mac80211_hwsim(const std::string & path)387 void CuttlefishConfig::set_vhost_user_mac80211_hwsim(const std::string& path) {
388 (*dictionary_)[kVhostUserMac80211Hwsim] = path;
389 }
vhost_user_mac80211_hwsim() const390 std::string CuttlefishConfig::vhost_user_mac80211_hwsim() const {
391 return (*dictionary_)[kVhostUserMac80211Hwsim].asString();
392 }
393
394 static constexpr char kWmediumdApiServerSocket[] = "wmediumd_api_server_socket";
set_wmediumd_api_server_socket(const std::string & path)395 void CuttlefishConfig::set_wmediumd_api_server_socket(const std::string& path) {
396 (*dictionary_)[kWmediumdApiServerSocket] = path;
397 }
wmediumd_api_server_socket() const398 std::string CuttlefishConfig::wmediumd_api_server_socket() const {
399 return (*dictionary_)[kWmediumdApiServerSocket].asString();
400 }
401
402 static constexpr char kApRootfsImage[] = "ap_rootfs_image";
ap_rootfs_image() const403 std::string CuttlefishConfig::ap_rootfs_image() const {
404 return (*dictionary_)[kApRootfsImage].asString();
405 }
set_ap_rootfs_image(const std::string & ap_rootfs_image)406 void CuttlefishConfig::set_ap_rootfs_image(const std::string& ap_rootfs_image) {
407 (*dictionary_)[kApRootfsImage] = ap_rootfs_image;
408 }
409
410 static constexpr char kApKernelImage[] = "ap_kernel_image";
ap_kernel_image() const411 std::string CuttlefishConfig::ap_kernel_image() const {
412 return (*dictionary_)[kApKernelImage].asString();
413 }
set_ap_kernel_image(const std::string & ap_kernel_image)414 void CuttlefishConfig::set_ap_kernel_image(const std::string& ap_kernel_image) {
415 (*dictionary_)[kApKernelImage] = ap_kernel_image;
416 }
417
418 static constexpr char kWmediumdConfig[] = "wmediumd_config";
set_wmediumd_config(const std::string & config)419 void CuttlefishConfig::set_wmediumd_config(const std::string& config) {
420 (*dictionary_)[kWmediumdConfig] = config;
421 }
wmediumd_config() const422 std::string CuttlefishConfig::wmediumd_config() const {
423 return (*dictionary_)[kWmediumdConfig].asString();
424 }
425
426 static constexpr char kRootcanalArgs[] = "rootcanal_args";
set_rootcanal_args(const std::string & rootcanal_args)427 void CuttlefishConfig::set_rootcanal_args(const std::string& rootcanal_args) {
428 Json::Value args_json_obj(Json::arrayValue);
429 for (const auto& arg : android::base::Split(rootcanal_args, " ")) {
430 args_json_obj.append(arg);
431 }
432 (*dictionary_)[kRootcanalArgs] = args_json_obj;
433 }
rootcanal_args() const434 std::vector<std::string> CuttlefishConfig::rootcanal_args() const {
435 std::vector<std::string> rootcanal_args;
436 for (const Json::Value& arg : (*dictionary_)[kRootcanalArgs]) {
437 rootcanal_args.push_back(arg.asString());
438 }
439 return rootcanal_args;
440 }
441
442 static constexpr char kRootcanalHciPort[] = "rootcanal_hci_port";
rootcanal_hci_port() const443 int CuttlefishConfig::rootcanal_hci_port() const {
444 return (*dictionary_)[kRootcanalHciPort].asInt();
445 }
set_rootcanal_hci_port(int rootcanal_hci_port)446 void CuttlefishConfig::set_rootcanal_hci_port(int rootcanal_hci_port) {
447 (*dictionary_)[kRootcanalHciPort] = rootcanal_hci_port;
448 }
449
450 static constexpr char kRootcanalLinkPort[] = "rootcanal_link_port";
rootcanal_link_port() const451 int CuttlefishConfig::rootcanal_link_port() const {
452 return (*dictionary_)[kRootcanalLinkPort].asInt();
453 }
set_rootcanal_link_port(int rootcanal_link_port)454 void CuttlefishConfig::set_rootcanal_link_port(int rootcanal_link_port) {
455 (*dictionary_)[kRootcanalLinkPort] = rootcanal_link_port;
456 }
457
458 static constexpr char kRootcanalLinkBlePort[] = "rootcanal_link_ble_port";
rootcanal_link_ble_port() const459 int CuttlefishConfig::rootcanal_link_ble_port() const {
460 return (*dictionary_)[kRootcanalLinkBlePort].asInt();
461 }
set_rootcanal_link_ble_port(int rootcanal_link_ble_port)462 void CuttlefishConfig::set_rootcanal_link_ble_port(
463 int rootcanal_link_ble_port) {
464 (*dictionary_)[kRootcanalLinkBlePort] = rootcanal_link_ble_port;
465 }
466
467 static constexpr char kRootcanalTestPort[] = "rootcanal_test_port";
rootcanal_test_port() const468 int CuttlefishConfig::rootcanal_test_port() const {
469 return (*dictionary_)[kRootcanalTestPort].asInt();
470 }
set_rootcanal_test_port(int rootcanal_test_port)471 void CuttlefishConfig::set_rootcanal_test_port(int rootcanal_test_port) {
472 (*dictionary_)[kRootcanalTestPort] = rootcanal_test_port;
473 }
474
475 static constexpr char kRootcanalConfigFile[] = "rootcanal_config_file";
rootcanal_config_file() const476 std::string CuttlefishConfig::rootcanal_config_file() const {
477 return (*dictionary_)[kRootcanalConfigFile].asString();
478 }
set_rootcanal_config_file(const std::string & rootcanal_config_file)479 void CuttlefishConfig::set_rootcanal_config_file(
480 const std::string& rootcanal_config_file) {
481 (*dictionary_)[kRootcanalConfigFile] =
482 DefaultHostArtifactsPath(rootcanal_config_file);
483 }
484
485 static constexpr char kRootcanalDefaultCommandsFile[] =
486 "rootcanal_default_commands_file";
rootcanal_default_commands_file() const487 std::string CuttlefishConfig::rootcanal_default_commands_file() const {
488 return (*dictionary_)[kRootcanalDefaultCommandsFile].asString();
489 }
set_rootcanal_default_commands_file(const std::string & rootcanal_default_commands_file)490 void CuttlefishConfig::set_rootcanal_default_commands_file(
491 const std::string& rootcanal_default_commands_file) {
492 (*dictionary_)[kRootcanalDefaultCommandsFile] =
493 DefaultHostArtifactsPath(rootcanal_default_commands_file);
494 }
495
BuildConfigImpl(const std::string & path)496 /*static*/ CuttlefishConfig* CuttlefishConfig::BuildConfigImpl(
497 const std::string& path) {
498 auto ret = new CuttlefishConfig();
499 if (ret) {
500 auto loaded = ret->LoadFromFile(path.c_str());
501 if (!loaded) {
502 delete ret;
503 return nullptr;
504 }
505 }
506 return ret;
507 }
508
509 /*static*/ std::unique_ptr<const CuttlefishConfig>
GetFromFile(const std::string & path)510 CuttlefishConfig::GetFromFile(const std::string& path) {
511 return std::unique_ptr<const CuttlefishConfig>(BuildConfigImpl(path));
512 }
513
514 // Creates the (initially empty) config object and populates it with values from
515 // the config file if the CUTTLEFISH_CONFIG_FILE env variable is present.
516 // Returns nullptr if there was an error loading from file
Get()517 /*static*/ const CuttlefishConfig* CuttlefishConfig::Get() {
518 auto config_file_path =
519 StringFromEnv(kCuttlefishConfigEnvVarName, GetGlobalConfigFileLink());
520 static std::shared_ptr<CuttlefishConfig> config(
521 BuildConfigImpl(config_file_path));
522 return config.get();
523 }
524
ConfigExists()525 /*static*/ bool CuttlefishConfig::ConfigExists() {
526 auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName,
527 GetGlobalConfigFileLink());
528 auto real_file_path = AbsolutePath(config_file_path.c_str());
529 return FileExists(real_file_path);
530 }
531
CuttlefishConfig()532 CuttlefishConfig::CuttlefishConfig() : dictionary_(new Json::Value()) {}
533 // Can't use '= default' on the header because the compiler complains of
534 // Json::Value being an incomplete type
535 CuttlefishConfig::~CuttlefishConfig() = default;
536
537 CuttlefishConfig::CuttlefishConfig(CuttlefishConfig&&) = default;
538 CuttlefishConfig& CuttlefishConfig::operator=(CuttlefishConfig&&) = default;
539
LoadFromFile(const char * file)540 bool CuttlefishConfig::LoadFromFile(const char* file) {
541 auto real_file_path = AbsolutePath(file);
542 if (real_file_path.empty()) {
543 LOG(ERROR) << "Could not get real path for file " << file;
544 return false;
545 }
546 Json::CharReaderBuilder builder;
547 std::ifstream ifs(real_file_path);
548 std::string errorMessage;
549 if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
550 LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage;
551 return false;
552 }
553 return true;
554 }
SaveToFile(const std::string & file) const555 bool CuttlefishConfig::SaveToFile(const std::string& file) const {
556 std::ofstream ofs(file);
557 if (!ofs.is_open()) {
558 LOG(ERROR) << "Unable to write to file " << file;
559 return false;
560 }
561 ofs << *dictionary_;
562 return !ofs.fail();
563 }
564
instances_dir() const565 std::string CuttlefishConfig::instances_dir() const {
566 return AbsolutePath(root_dir() + "/instances");
567 }
568
InstancesPath(const std::string & file_name) const569 std::string CuttlefishConfig::InstancesPath(
570 const std::string& file_name) const {
571 return AbsolutePath(instances_dir() + "/" + file_name);
572 }
573
assembly_dir() const574 std::string CuttlefishConfig::assembly_dir() const {
575 return AbsolutePath(root_dir() + "/assembly");
576 }
577
AssemblyPath(const std::string & file_name) const578 std::string CuttlefishConfig::AssemblyPath(
579 const std::string& file_name) const {
580 return AbsolutePath(assembly_dir() + "/" + file_name);
581 }
582
instances_uds_dir() const583 std::string CuttlefishConfig::instances_uds_dir() const {
584 // Try to use /tmp/cf_avd_{uid}/ for UDS directory.
585 // If it fails, use HOME directory(legacy) instead.
586
587 auto defaultPath = AbsolutePath("/tmp/cf_avd_" + std::to_string(getuid()));
588
589 if (!DirectoryExists(defaultPath) ||
590 CanAccess(defaultPath, R_OK | W_OK | X_OK)) {
591 return defaultPath;
592 }
593
594 return instances_dir();
595 }
596
InstancesUdsPath(const std::string & file_name) const597 std::string CuttlefishConfig::InstancesUdsPath(
598 const std::string& file_name) const {
599 return AbsolutePath(instances_uds_dir() + "/" + file_name);
600 }
601
ForInstance(int num)602 CuttlefishConfig::MutableInstanceSpecific CuttlefishConfig::ForInstance(int num) {
603 return MutableInstanceSpecific(this, std::to_string(num));
604 }
605
ForInstance(int num) const606 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstance(int num) const {
607 return InstanceSpecific(this, std::to_string(num));
608 }
609
ForInstanceName(const std::string & name) const610 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstanceName(
611 const std::string& name) const {
612 return ForInstance(InstanceFromString(name));
613 }
614
ForDefaultInstance() const615 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForDefaultInstance() const {
616 return ForInstance(GetInstance());
617 }
618
Instances() const619 std::vector<CuttlefishConfig::InstanceSpecific> CuttlefishConfig::Instances() const {
620 const auto& json = (*dictionary_)[kInstances];
621 std::vector<CuttlefishConfig::InstanceSpecific> instances;
622 for (const auto& name : json.getMemberNames()) {
623 instances.push_back(CuttlefishConfig::InstanceSpecific(this, name));
624 }
625 return instances;
626 }
627
instance_dirs() const628 std::vector<std::string> CuttlefishConfig::instance_dirs() const {
629 std::vector<std::string> result;
630 for (const auto& instance : Instances()) {
631 result.push_back(instance.instance_dir());
632 result.push_back(instance.instance_uds_dir());
633 }
634 return result;
635 }
636
637 static constexpr char kInstanceNames[] = "instance_names";
set_instance_names(const std::vector<std::string> & instance_names)638 void CuttlefishConfig::set_instance_names(
639 const std::vector<std::string>& instance_names) {
640 Json::Value args_json_obj(Json::arrayValue);
641 for (const auto& name : instance_names) {
642 args_json_obj.append(name);
643 }
644 (*dictionary_)[kInstanceNames] = args_json_obj;
645 }
instance_names() const646 std::vector<std::string> CuttlefishConfig::instance_names() const {
647 // NOTE: The structure of this field needs to remain stable, since
648 // cvd_server may call this on config JSON files from various builds.
649 //
650 // This info is duplicated into its own field here so it is simpler
651 // to keep stable, rather than parsing from Instances()::instance_name.
652 //
653 // Any non-stable changes must be accompanied by an uprev to the
654 // cvd_server major version.
655 std::vector<std::string> names;
656 for (const Json::Value& name : (*dictionary_)[kInstanceNames]) {
657 names.push_back(name.asString());
658 }
659 return names;
660 }
661
GetInstance()662 int GetInstance() {
663 static int instance_id = InstanceFromEnvironment();
664 return instance_id;
665 }
666
GetDefaultVsockCid()667 int GetDefaultVsockCid() {
668 // we assume that this function is used to configure CuttlefishConfig once
669 static const int default_vsock_cid = 3 + GetInstance() - 1;
670 return default_vsock_cid;
671 }
672
GetVsockServerPort(const int base,const int vsock_guest_cid)673 int GetVsockServerPort(const int base,
674 const int vsock_guest_cid /**< per instance guest cid */) {
675 return base + (vsock_guest_cid - 3);
676 }
677
GetGlobalConfigFileLink()678 std::string GetGlobalConfigFileLink() {
679 return StringFromEnv("HOME", ".") + "/.cuttlefish_config.json";
680 }
681
ForCurrentInstance(const char * prefix)682 std::string ForCurrentInstance(const char* prefix) {
683 std::ostringstream stream;
684 stream << prefix << std::setfill('0') << std::setw(2) << GetInstance();
685 return stream.str();
686 }
ForCurrentInstance(int base)687 int ForCurrentInstance(int base) { return base + GetInstance() - 1; }
688
RandomSerialNumber(const std::string & prefix)689 std::string RandomSerialNumber(const std::string& prefix) {
690 const char hex_characters[] = "0123456789ABCDEF";
691 std::srand(time(0));
692 char str[10];
693 for(int i=0; i<10; i++){
694 str[i] = hex_characters[rand() % strlen(hex_characters)];
695 }
696 return prefix + str;
697 }
698
DefaultHostArtifactsPath(const std::string & file_name)699 std::string DefaultHostArtifactsPath(const std::string& file_name) {
700 return (StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) + "/") +
701 file_name;
702 }
703
HostBinaryPath(const std::string & binary_name)704 std::string HostBinaryPath(const std::string& binary_name) {
705 #ifdef __ANDROID__
706 return binary_name;
707 #else
708 return DefaultHostArtifactsPath("bin/" + binary_name);
709 #endif
710 }
711
DefaultGuestImagePath(const std::string & file_name)712 std::string DefaultGuestImagePath(const std::string& file_name) {
713 return (StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", "."))) +
714 file_name;
715 }
716
HostSupportsQemuCli()717 bool HostSupportsQemuCli() {
718 static bool supported =
719 std::system(
720 "/usr/lib/cuttlefish-common/bin/capability_query.py qemu_cli") == 0;
721 return supported;
722 }
723
724 } // namespace cuttlefish
725