/* * Copyright (C) 2018 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. */ #include "host/libs/config/cuttlefish_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/libs/utils/environment.h" #include "common/libs/utils/files.h" #include "host/libs/vm_manager/crosvm_manager.h" #include "host/libs/vm_manager/gem5_manager.h" #include "host/libs/vm_manager/qemu_manager.h" namespace cuttlefish { namespace { const char* kInstances = "instances"; } // namespace const char* const kVhostUserVsockModeAuto = "auto"; const char* const kVhostUserVsockModeTrue = "true"; const char* const kVhostUserVsockModeFalse = "false"; const char* const kGpuModeAuto = "auto"; const char* const kGpuModeCustom = "custom"; const char* const kGpuModeDrmVirgl = "drm_virgl"; const char* const kGpuModeGfxstream = "gfxstream"; const char* const kGpuModeGfxstreamGuestAngle = "gfxstream_guest_angle"; const char* const kGpuModeGfxstreamGuestAngleHostSwiftShader = "gfxstream_guest_angle_host_swiftshader"; const char* const kGpuModeGuestSwiftshader = "guest_swiftshader"; const char* const kGpuModeNone = "none"; const char* const kGpuVhostUserModeAuto = "auto"; const char* const kGpuVhostUserModeOn = "on"; const char* const kGpuVhostUserModeOff = "off"; const char* const kHwComposerAuto = "auto"; const char* const kHwComposerDrm = "drm_hwcomposer"; const char* const kHwComposerRanchu = "ranchu"; const char* const kHwComposerNone = "none"; std::string DefaultEnvironmentPath(const char* environment_key, const char* default_value, const char* subpath) { return StringFromEnv(environment_key, default_value) + "/" + subpath; } bool IsRestoring(const CuttlefishConfig& config) { return FileExists(config.AssemblyPath("restore")); } ConfigFragment::~ConfigFragment() = default; static constexpr char kFragments[] = "fragments"; bool CuttlefishConfig::LoadFragment(ConfigFragment& fragment) const { if (!dictionary_->isMember(kFragments)) { LOG(ERROR) << "Fragments member was missing"; return false; } const Json::Value& json_fragments = (*dictionary_)[kFragments]; if (!json_fragments.isMember(fragment.Name())) { LOG(ERROR) << "Could not find a fragment called " << fragment.Name(); return false; } return fragment.Deserialize(json_fragments[fragment.Name()]); } bool CuttlefishConfig::SaveFragment(const ConfigFragment& fragment) { Json::Value& json_fragments = (*dictionary_)[kFragments]; if (json_fragments.isMember(fragment.Name())) { LOG(ERROR) << "Already have a fragment called " << fragment.Name(); return false; } json_fragments[fragment.Name()] = fragment.Serialize(); return true; } static constexpr char kRootDir[] = "root_dir"; std::string CuttlefishConfig::root_dir() const { return (*dictionary_)[kRootDir].asString(); } void CuttlefishConfig::set_root_dir(const std::string& root_dir) { (*dictionary_)[kRootDir] = root_dir; } static constexpr char kVmManager[] = "vm_manager"; VmmMode CuttlefishConfig::vm_manager() const { auto str = (*dictionary_)[kVmManager].asString(); return ParseVmm(str).value_or(VmmMode::kUnknown); } void CuttlefishConfig::set_vm_manager(VmmMode vmm) { (*dictionary_)[kVmManager] = fmt::format("{}", vmm); } static constexpr char kApVmManager[] = "ap_vm_manager"; std::string CuttlefishConfig::ap_vm_manager() const { return (*dictionary_)[kApVmManager].asString(); } void CuttlefishConfig::set_ap_vm_manager(const std::string& name) { (*dictionary_)[kApVmManager] = name; } static constexpr char kSecureHals[] = "secure_hals"; Result> CuttlefishConfig::secure_hals() const { std::set args_set; for (auto& hal : (*dictionary_)[kSecureHals]) { args_set.insert(CF_EXPECT(ParseSecureHal(hal.asString()))); } return args_set; } void CuttlefishConfig::set_secure_hals(const std::set& hals) { Json::Value hals_json_obj(Json::arrayValue); for (const auto& hal : hals) { hals_json_obj.append(ToString(hal)); } (*dictionary_)[kSecureHals] = hals_json_obj; } static constexpr char kCrosvmBinary[] = "crosvm_binary"; std::string CuttlefishConfig::crosvm_binary() const { return (*dictionary_)[kCrosvmBinary].asString(); } void CuttlefishConfig::set_crosvm_binary(const std::string& crosvm_binary) { (*dictionary_)[kCrosvmBinary] = crosvm_binary; } bool CuttlefishConfig::IsCrosvm() const { return vm_manager() == VmmMode::kCrosvm; } static constexpr char kGem5DebugFlags[] = "gem5_debug_flags"; std::string CuttlefishConfig::gem5_debug_flags() const { return (*dictionary_)[kGem5DebugFlags].asString(); } void CuttlefishConfig::set_gem5_debug_flags(const std::string& gem5_debug_flags) { (*dictionary_)[kGem5DebugFlags] = gem5_debug_flags; } static constexpr char kWebRTCCertsDir[] = "webrtc_certs_dir"; void CuttlefishConfig::set_webrtc_certs_dir(const std::string& certs_dir) { (*dictionary_)[kWebRTCCertsDir] = certs_dir; } std::string CuttlefishConfig::webrtc_certs_dir() const { return (*dictionary_)[kWebRTCCertsDir].asString(); } static constexpr char kSigServerPort[] = "webrtc_sig_server_port"; void CuttlefishConfig::set_sig_server_port(int port) { (*dictionary_)[kSigServerPort] = port; } int CuttlefishConfig::sig_server_port() const { return (*dictionary_)[kSigServerPort].asInt(); } static constexpr char kSigServerAddress[] = "webrtc_sig_server_addr"; void CuttlefishConfig::set_sig_server_address(const std::string& addr) { (*dictionary_)[kSigServerAddress] = addr; } std::string CuttlefishConfig::sig_server_address() const { return (*dictionary_)[kSigServerAddress].asString(); } static constexpr char kSigServerPath[] = "webrtc_sig_server_path"; void CuttlefishConfig::set_sig_server_path(const std::string& path) { // Don't use SetPath here, it's a URL path not a file system path (*dictionary_)[kSigServerPath] = path; } std::string CuttlefishConfig::sig_server_path() const { return (*dictionary_)[kSigServerPath].asString(); } static constexpr char kSigServerSecure[] = "webrtc_sig_server_secure"; void CuttlefishConfig::set_sig_server_secure(bool secure) { (*dictionary_)[kSigServerSecure] = secure; } bool CuttlefishConfig::sig_server_secure() const { return (*dictionary_)[kSigServerSecure].asBool(); } static constexpr char kSigServerStrict[] = "webrtc_sig_server_strict"; void CuttlefishConfig::set_sig_server_strict(bool strict) { (*dictionary_)[kSigServerStrict] = strict; } bool CuttlefishConfig::sig_server_strict() const { return (*dictionary_)[kSigServerStrict].asBool(); } static constexpr char kHostToolsVersion[] = "host_tools_version"; void CuttlefishConfig::set_host_tools_version( const std::map& versions) { Json::Value json(Json::objectValue); for (const auto& [key, value] : versions) { json[key] = value; } (*dictionary_)[kHostToolsVersion] = json; } std::map CuttlefishConfig::host_tools_version() const { if (!dictionary_->isMember(kHostToolsVersion)) { return {}; } std::map versions; const auto& elem = (*dictionary_)[kHostToolsVersion]; for (auto it = elem.begin(); it != elem.end(); it++) { versions[it.key().asString()] = it->asUInt(); } return versions; } static constexpr char kEnableHostUwb[] = "enable_host_uwb"; void CuttlefishConfig::set_enable_host_uwb(bool enable_host_uwb) { (*dictionary_)[kEnableHostUwb] = enable_host_uwb; } bool CuttlefishConfig::enable_host_uwb() const { return (*dictionary_)[kEnableHostUwb].asBool(); } static constexpr char kEnableHostUwbConnector[] = "enable_host_uwb_connector"; void CuttlefishConfig::set_enable_host_uwb_connector(bool enable_host_uwb) { (*dictionary_)[kEnableHostUwbConnector] = enable_host_uwb; } bool CuttlefishConfig::enable_host_uwb_connector() const { return (*dictionary_)[kEnableHostUwbConnector].asBool(); } static constexpr char kPicaUciPort[] = "pica_uci_port"; int CuttlefishConfig::pica_uci_port() const { return (*dictionary_)[kPicaUciPort].asInt(); } void CuttlefishConfig::set_pica_uci_port(int pica_uci_port) { (*dictionary_)[kPicaUciPort] = pica_uci_port; } static constexpr char kEnableHostBluetooth[] = "enable_host_bluetooth"; void CuttlefishConfig::set_enable_host_bluetooth(bool enable_host_bluetooth) { (*dictionary_)[kEnableHostBluetooth] = enable_host_bluetooth; } bool CuttlefishConfig::enable_host_bluetooth() const { return (*dictionary_)[kEnableHostBluetooth].asBool(); } static constexpr char kEnableHostBluetoothConnector[] = "enable_host_bluetooth_connector"; void CuttlefishConfig::set_enable_host_bluetooth_connector(bool enable_host_bluetooth) { (*dictionary_)[kEnableHostBluetoothConnector] = enable_host_bluetooth; } bool CuttlefishConfig::enable_host_bluetooth_connector() const { return (*dictionary_)[kEnableHostBluetoothConnector].asBool(); } static constexpr char kEnableAutomotiveProxy[] = "enable_automotive_proxy"; void CuttlefishConfig::set_enable_automotive_proxy( bool enable_automotive_proxy) { (*dictionary_)[kEnableAutomotiveProxy] = enable_automotive_proxy; } bool CuttlefishConfig::enable_automotive_proxy() const { return (*dictionary_)[kEnableAutomotiveProxy].asBool(); } static constexpr char kVhalProxyServerPort[] = "vhal_proxy_server_port"; void CuttlefishConfig::set_vhal_proxy_server_port(int port) { (*dictionary_)[kVhalProxyServerPort] = port; } int CuttlefishConfig::vhal_proxy_server_port() const { return (*dictionary_)[kVhalProxyServerPort].asInt(); } static constexpr char kEnableHostNfc[] = "enable_host_nfc"; void CuttlefishConfig::set_enable_host_nfc(bool enable_host_nfc) { (*dictionary_)[kEnableHostNfc] = enable_host_nfc; } bool CuttlefishConfig::enable_host_nfc() const { return (*dictionary_)[kEnableHostNfc].asBool(); } static constexpr char kEnableHostNfcConnector[] = "enable_host_nfc_connector"; void CuttlefishConfig::set_enable_host_nfc_connector(bool enable_host_nfc) { (*dictionary_)[kEnableHostNfcConnector] = enable_host_nfc; } bool CuttlefishConfig::enable_host_nfc_connector() const { return (*dictionary_)[kEnableHostNfcConnector].asBool(); } static constexpr char kCasimirInstanceNum[] = "casimir_instance_num"; void CuttlefishConfig::set_casimir_instance_num(int casimir_instance_num) { (*dictionary_)[kCasimirInstanceNum] = casimir_instance_num; } int CuttlefishConfig::casimir_instance_num() const { return (*dictionary_)[kCasimirInstanceNum].asInt(); } static constexpr char kCasimirArgs[] = "casimir_args"; void CuttlefishConfig::set_casimir_args(const std::string& casimir_args) { Json::Value args_json_obj(Json::arrayValue); for (const auto& arg : android::base::Split(casimir_args, " ")) { if (!arg.empty()) { args_json_obj.append(arg); } } (*dictionary_)[kCasimirArgs] = args_json_obj; } std::vector CuttlefishConfig::casimir_args() const { std::vector casimir_args; for (const Json::Value& arg : (*dictionary_)[kCasimirArgs]) { casimir_args.push_back(arg.asString()); } return casimir_args; } static constexpr char kCasimirNciPort[] = "casimir_nci_port"; void CuttlefishConfig::set_casimir_nci_port(int port) { (*dictionary_)[kCasimirNciPort] = port; } int CuttlefishConfig::casimir_nci_port() const { return (*dictionary_)[kCasimirNciPort].asInt(); } static constexpr char kCasimirRfPort[] = "casimir_rf_port"; void CuttlefishConfig::set_casimir_rf_port(int port) { (*dictionary_)[kCasimirRfPort] = port; } int CuttlefishConfig::casimir_rf_port() const { return (*dictionary_)[kCasimirRfPort].asInt(); } static constexpr char kNetsimRadios[] = "netsim_radios"; void CuttlefishConfig::netsim_radio_enable(NetsimRadio flag) { if (dictionary_->isMember(kNetsimRadios)) { // OR the radio to current set of radios (*dictionary_)[kNetsimRadios] = (*dictionary_)[kNetsimRadios].asInt() | flag; } else { (*dictionary_)[kNetsimRadios] = flag; } } bool CuttlefishConfig::netsim_radio_enabled(NetsimRadio flag) const { return (*dictionary_)[kNetsimRadios].asInt() & flag; } static constexpr char kNetsimInstanceNum[] = "netsim_instance_num"; int CuttlefishConfig::netsim_instance_num() const { return (*dictionary_)[kNetsimInstanceNum].asInt(); } void CuttlefishConfig::set_netsim_instance_num(int netsim_instance_num) { (*dictionary_)[kNetsimInstanceNum] = netsim_instance_num; } static constexpr char kNetsimConnectorInstanceNum[] = "netsim_connector_instance_num"; int CuttlefishConfig::netsim_connector_instance_num() const { return (*dictionary_)[kNetsimConnectorInstanceNum].asInt(); } void CuttlefishConfig::set_netsim_connector_instance_num( int netsim_instance_num) { (*dictionary_)[kNetsimConnectorInstanceNum] = netsim_instance_num; } static constexpr char kNetsimArgs[] = "netsim_args"; void CuttlefishConfig::set_netsim_args(const std::string& netsim_args) { Json::Value args_json_obj(Json::arrayValue); for (const auto& arg : android::base::Tokenize(netsim_args, " ")) { args_json_obj.append(arg); } (*dictionary_)[kNetsimArgs] = args_json_obj; } std::vector CuttlefishConfig::netsim_args() const { std::vector netsim_args; for (const Json::Value& arg : (*dictionary_)[kNetsimArgs]) { netsim_args.push_back(arg.asString()); } return netsim_args; } static constexpr char kEnableMetrics[] = "enable_metrics"; void CuttlefishConfig::set_enable_metrics(std::string enable_metrics) { (*dictionary_)[kEnableMetrics] = static_cast(cuttlefish::CuttlefishConfig::Answer::kUnknown); if (!enable_metrics.empty()) { switch (enable_metrics.at(0)) { case 'y': case 'Y': (*dictionary_)[kEnableMetrics] = static_cast(cuttlefish::CuttlefishConfig::Answer::kYes); break; case 'n': case 'N': (*dictionary_)[kEnableMetrics] = static_cast(cuttlefish::CuttlefishConfig::Answer::kNo); break; } } } // validate the casting and conversion from json configs to // CuttlefishConfig::Answer class bool IsValidMetricsConfigs(int value) { return value == static_cast(CuttlefishConfig::Answer::kUnknown) || value == static_cast(CuttlefishConfig::Answer::kNo) || value == static_cast(CuttlefishConfig::Answer::kYes); } CuttlefishConfig::Answer CuttlefishConfig::enable_metrics() const { int value = (*dictionary_)[kEnableMetrics].asInt(); if (!IsValidMetricsConfigs(value)) { LOG(ERROR) << "Invalid integer value for Answer enum"; return static_cast(CuttlefishConfig::Answer::kUnknown); } return static_cast(value); } static constexpr char kMetricsBinary[] = "metrics_binary"; void CuttlefishConfig::set_metrics_binary(const std::string& metrics_binary) { (*dictionary_)[kMetricsBinary] = metrics_binary; } std::string CuttlefishConfig::metrics_binary() const { return (*dictionary_)[kMetricsBinary].asString(); } static constexpr char kExtraKernelCmdline[] = "extra_kernel_cmdline"; void CuttlefishConfig::set_extra_kernel_cmdline( const std::string& extra_cmdline) { Json::Value args_json_obj(Json::arrayValue); for (const auto& arg : android::base::Split(extra_cmdline, " ")) { args_json_obj.append(arg); } (*dictionary_)[kExtraKernelCmdline] = args_json_obj; } std::vector CuttlefishConfig::extra_kernel_cmdline() const { std::vector cmdline; for (const Json::Value& arg : (*dictionary_)[kExtraKernelCmdline]) { cmdline.push_back(arg.asString()); } return cmdline; } static constexpr char kVirtioMac80211Hwsim[] = "virtio_mac80211_hwsim"; void CuttlefishConfig::set_virtio_mac80211_hwsim(bool virtio_mac80211_hwsim) { (*dictionary_)[kVirtioMac80211Hwsim] = virtio_mac80211_hwsim; } bool CuttlefishConfig::virtio_mac80211_hwsim() const { return (*dictionary_)[kVirtioMac80211Hwsim].asBool(); } static constexpr char kApRootfsImage[] = "ap_rootfs_image"; std::string CuttlefishConfig::ap_rootfs_image() const { return (*dictionary_)[kApRootfsImage].asString(); } void CuttlefishConfig::set_ap_rootfs_image(const std::string& ap_rootfs_image) { (*dictionary_)[kApRootfsImage] = ap_rootfs_image; } static constexpr char kApKernelImage[] = "ap_kernel_image"; std::string CuttlefishConfig::ap_kernel_image() const { return (*dictionary_)[kApKernelImage].asString(); } void CuttlefishConfig::set_ap_kernel_image(const std::string& ap_kernel_image) { (*dictionary_)[kApKernelImage] = ap_kernel_image; } static constexpr char kRootcanalArgs[] = "rootcanal_args"; void CuttlefishConfig::set_rootcanal_args(const std::string& rootcanal_args) { Json::Value args_json_obj(Json::arrayValue); for (const auto& arg : android::base::Split(rootcanal_args, " ")) { args_json_obj.append(arg); } (*dictionary_)[kRootcanalArgs] = args_json_obj; } std::vector CuttlefishConfig::rootcanal_args() const { std::vector rootcanal_args; for (const Json::Value& arg : (*dictionary_)[kRootcanalArgs]) { rootcanal_args.push_back(arg.asString()); } return rootcanal_args; } static constexpr char kRootcanalHciPort[] = "rootcanal_hci_port"; int CuttlefishConfig::rootcanal_hci_port() const { return (*dictionary_)[kRootcanalHciPort].asInt(); } void CuttlefishConfig::set_rootcanal_hci_port(int rootcanal_hci_port) { (*dictionary_)[kRootcanalHciPort] = rootcanal_hci_port; } static constexpr char kRootcanalLinkPort[] = "rootcanal_link_port"; int CuttlefishConfig::rootcanal_link_port() const { return (*dictionary_)[kRootcanalLinkPort].asInt(); } void CuttlefishConfig::set_rootcanal_link_port(int rootcanal_link_port) { (*dictionary_)[kRootcanalLinkPort] = rootcanal_link_port; } static constexpr char kRootcanalLinkBlePort[] = "rootcanal_link_ble_port"; int CuttlefishConfig::rootcanal_link_ble_port() const { return (*dictionary_)[kRootcanalLinkBlePort].asInt(); } void CuttlefishConfig::set_rootcanal_link_ble_port( int rootcanal_link_ble_port) { (*dictionary_)[kRootcanalLinkBlePort] = rootcanal_link_ble_port; } static constexpr char kRootcanalTestPort[] = "rootcanal_test_port"; int CuttlefishConfig::rootcanal_test_port() const { return (*dictionary_)[kRootcanalTestPort].asInt(); } void CuttlefishConfig::set_rootcanal_test_port(int rootcanal_test_port) { (*dictionary_)[kRootcanalTestPort] = rootcanal_test_port; } static constexpr char kSnapshotPath[] = "snapshot_path"; std::string CuttlefishConfig::snapshot_path() const { return (*dictionary_)[kSnapshotPath].asString(); } void CuttlefishConfig::set_snapshot_path(const std::string& snapshot_path) { (*dictionary_)[kSnapshotPath] = snapshot_path; } static constexpr char kStracedExecutables[] = "straced_host_executables"; void CuttlefishConfig::set_straced_host_executables( const std::set& straced_host_executables) { Json::Value args_json_obj(Json::arrayValue); for (const auto& arg : straced_host_executables) { args_json_obj.append(arg); } (*dictionary_)[kStracedExecutables] = args_json_obj; } std::set CuttlefishConfig::straced_host_executables() const { std::set straced_host_executables; for (const Json::Value& arg : (*dictionary_)[kStracedExecutables]) { straced_host_executables.insert(arg.asString()); } return straced_host_executables; } /*static*/ CuttlefishConfig* CuttlefishConfig::BuildConfigImpl( const std::string& path) { auto ret = new CuttlefishConfig(); if (ret) { auto loaded = ret->LoadFromFile(path.c_str()); if (!loaded) { delete ret; return nullptr; } } return ret; } /*static*/ std::unique_ptr CuttlefishConfig::GetFromFile(const std::string& path) { return std::unique_ptr(BuildConfigImpl(path)); } // Creates the (initially empty) config object and populates it with values from // the config file if the CUTTLEFISH_CONFIG_FILE env variable is present. // Returns nullptr if there was an error loading from file /*static*/ const CuttlefishConfig* CuttlefishConfig::Get() { auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName, GetGlobalConfigFileLink()); static std::shared_ptr config( BuildConfigImpl(config_file_path)); return config.get(); } /*static*/ bool CuttlefishConfig::ConfigExists() { auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName, GetGlobalConfigFileLink()); auto real_file_path = AbsolutePath(config_file_path.c_str()); return FileExists(real_file_path); } CuttlefishConfig::CuttlefishConfig() : dictionary_(new Json::Value()) {} // Can't use '= default' on the header because the compiler complains of // Json::Value being an incomplete type CuttlefishConfig::~CuttlefishConfig() = default; CuttlefishConfig::CuttlefishConfig(CuttlefishConfig&&) = default; CuttlefishConfig& CuttlefishConfig::operator=(CuttlefishConfig&&) = default; bool CuttlefishConfig::LoadFromFile(const char* file) { auto real_file_path = AbsolutePath(file); if (real_file_path.empty()) { LOG(ERROR) << "Could not get real path for file " << file; return false; } Json::CharReaderBuilder builder; std::ifstream ifs(real_file_path); std::string errorMessage; if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) { LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage; return false; } return true; } bool CuttlefishConfig::SaveToFile(const std::string& file) const { std::ofstream ofs(file); if (!ofs.is_open()) { LOG(ERROR) << "Unable to write to file " << file; return false; } ofs << *dictionary_; return !ofs.fail(); } std::string CuttlefishConfig::instances_dir() const { return AbsolutePath(root_dir() + "/instances"); } std::string CuttlefishConfig::InstancesPath( const std::string& file_name) const { return AbsolutePath(instances_dir() + "/" + file_name); } std::string CuttlefishConfig::assembly_dir() const { return AbsolutePath(root_dir() + "/assembly"); } std::string CuttlefishConfig::AssemblyPath( const std::string& file_name) const { return AbsolutePath(assembly_dir() + "/" + file_name); } static constexpr char kInstancesUdsDir[] = "instances_uds_dir"; void CuttlefishConfig::set_instances_uds_dir(const std::string& dir) { (*dictionary_)[kInstancesUdsDir] = dir; } std::string CuttlefishConfig::instances_uds_dir() const { return (*dictionary_)[kInstancesUdsDir].asString(); } std::string CuttlefishConfig::InstancesUdsPath( const std::string& file_name) const { return AbsolutePath(instances_uds_dir() + "/" + file_name); } std::string CuttlefishConfig::environments_dir() const { return AbsolutePath(root_dir() + "/environments"); } std::string CuttlefishConfig::EnvironmentsPath( const std::string& file_name) const { return AbsolutePath(environments_dir() + "/" + file_name); } static constexpr char kEnvironmentsUdsDir[] = "environments_uds_dir"; void CuttlefishConfig::set_environments_uds_dir(const std::string& dir) { (*dictionary_)[kEnvironmentsUdsDir] = dir; } std::string CuttlefishConfig::environments_uds_dir() const { return (*dictionary_)[kEnvironmentsUdsDir].asString(); } std::string CuttlefishConfig::EnvironmentsUdsPath( const std::string& file_name) const { return AbsolutePath(environments_uds_dir() + "/" + file_name); } CuttlefishConfig::MutableInstanceSpecific CuttlefishConfig::ForInstance(int num) { return MutableInstanceSpecific(this, std::to_string(num)); } CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstance(int num) const { return InstanceSpecific(this, std::to_string(num)); } CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstanceName( const std::string& name) const { return ForInstance(InstanceFromString(name)); } CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForDefaultInstance() const { return ForInstance(GetInstance()); } std::vector CuttlefishConfig::Instances() const { const auto& json = (*dictionary_)[kInstances]; std::vector instances; for (const auto& name : json.getMemberNames()) { instances.push_back(CuttlefishConfig::InstanceSpecific(this, name)); } return instances; } std::vector CuttlefishConfig::instance_dirs() const { std::vector result; for (const auto& instance : Instances()) { result.push_back(instance.instance_dir()); result.push_back(instance.instance_uds_dir()); } return result; } static constexpr char kInstanceNames[] = "instance_names"; void CuttlefishConfig::set_instance_names( const std::vector& instance_names) { Json::Value args_json_obj(Json::arrayValue); for (const auto& name : instance_names) { args_json_obj.append(name); } (*dictionary_)[kInstanceNames] = args_json_obj; } std::vector CuttlefishConfig::instance_names() const { // NOTE: The structure of this field needs to remain stable, since // cvd_server may call this on config JSON files from various builds. // // This info is duplicated into its own field here so it is simpler // to keep stable, rather than parsing from Instances()::instance_name. // // Any non-stable changes must be accompanied by an uprev to the // cvd_server major version. std::vector names; for (const Json::Value& name : (*dictionary_)[kInstanceNames]) { names.push_back(name.asString()); } return names; } CuttlefishConfig::MutableEnvironmentSpecific CuttlefishConfig::ForEnvironment( const std::string& envName) { return MutableEnvironmentSpecific(this, envName); } CuttlefishConfig::EnvironmentSpecific CuttlefishConfig::ForEnvironment( const std::string& envName) const { return EnvironmentSpecific(this, envName); } CuttlefishConfig::MutableEnvironmentSpecific CuttlefishConfig::ForDefaultEnvironment() { return MutableEnvironmentSpecific(this, ForDefaultInstance().environment_name()); } CuttlefishConfig::EnvironmentSpecific CuttlefishConfig::ForDefaultEnvironment() const { return EnvironmentSpecific(this, ForDefaultInstance().environment_name()); } std::vector CuttlefishConfig::environment_dirs() const { auto environment = ForDefaultEnvironment(); std::vector result; result.push_back(environment.environment_dir()); result.push_back(environment.environment_uds_dir()); return result; } } // namespace cuttlefish