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 const char* kInstances = "instances";
45 
46 }  // namespace
47 
48 const char* const kVhostUserVsockModeAuto = "auto";
49 const char* const kVhostUserVsockModeTrue = "true";
50 const char* const kVhostUserVsockModeFalse = "false";
51 
52 const char* const kGpuModeAuto = "auto";
53 const char* const kGpuModeCustom = "custom";
54 const char* const kGpuModeDrmVirgl = "drm_virgl";
55 const char* const kGpuModeGfxstream = "gfxstream";
56 const char* const kGpuModeGfxstreamGuestAngle = "gfxstream_guest_angle";
57 const char* const kGpuModeGfxstreamGuestAngleHostSwiftShader =
58     "gfxstream_guest_angle_host_swiftshader";
59 const char* const kGpuModeGuestSwiftshader = "guest_swiftshader";
60 const char* const kGpuModeNone = "none";
61 
62 const char* const kGpuVhostUserModeAuto = "auto";
63 const char* const kGpuVhostUserModeOn = "on";
64 const char* const kGpuVhostUserModeOff = "off";
65 
66 const char* const kHwComposerAuto = "auto";
67 const char* const kHwComposerDrm = "drm_hwcomposer";
68 const char* const kHwComposerRanchu = "ranchu";
69 const char* const kHwComposerNone = "none";
70 
DefaultEnvironmentPath(const char * environment_key,const char * default_value,const char * subpath)71 std::string DefaultEnvironmentPath(const char* environment_key,
72                                    const char* default_value,
73                                    const char* subpath) {
74   return StringFromEnv(environment_key, default_value) + "/" + subpath;
75 }
76 
IsRestoring(const CuttlefishConfig & config)77 bool IsRestoring(const CuttlefishConfig& config) {
78   return FileExists(config.AssemblyPath("restore"));
79 }
80 ConfigFragment::~ConfigFragment() = default;
81 
82 static constexpr char kFragments[] = "fragments";
LoadFragment(ConfigFragment & fragment) const83 bool CuttlefishConfig::LoadFragment(ConfigFragment& fragment) const {
84   if (!dictionary_->isMember(kFragments)) {
85     LOG(ERROR) << "Fragments member was missing";
86     return false;
87   }
88   const Json::Value& json_fragments = (*dictionary_)[kFragments];
89   if (!json_fragments.isMember(fragment.Name())) {
90     LOG(ERROR) << "Could not find a fragment called " << fragment.Name();
91     return false;
92   }
93   return fragment.Deserialize(json_fragments[fragment.Name()]);
94 }
SaveFragment(const ConfigFragment & fragment)95 bool CuttlefishConfig::SaveFragment(const ConfigFragment& fragment) {
96   Json::Value& json_fragments = (*dictionary_)[kFragments];
97   if (json_fragments.isMember(fragment.Name())) {
98     LOG(ERROR) << "Already have a fragment called " << fragment.Name();
99     return false;
100   }
101   json_fragments[fragment.Name()] = fragment.Serialize();
102   return true;
103 }
104 
105 static constexpr char kRootDir[] = "root_dir";
root_dir() const106 std::string CuttlefishConfig::root_dir() const {
107   return (*dictionary_)[kRootDir].asString();
108 }
set_root_dir(const std::string & root_dir)109 void CuttlefishConfig::set_root_dir(const std::string& root_dir) {
110   (*dictionary_)[kRootDir] = root_dir;
111 }
112 
113 static constexpr char kVmManager[] = "vm_manager";
vm_manager() const114 VmmMode CuttlefishConfig::vm_manager() const {
115   auto str = (*dictionary_)[kVmManager].asString();
116   return ParseVmm(str).value_or(VmmMode::kUnknown);
117 }
set_vm_manager(VmmMode vmm)118 void CuttlefishConfig::set_vm_manager(VmmMode vmm) {
119   (*dictionary_)[kVmManager] = fmt::format("{}", vmm);
120 }
121 
122 static constexpr char kApVmManager[] = "ap_vm_manager";
ap_vm_manager() const123 std::string CuttlefishConfig::ap_vm_manager() const {
124   return (*dictionary_)[kApVmManager].asString();
125 }
set_ap_vm_manager(const std::string & name)126 void CuttlefishConfig::set_ap_vm_manager(const std::string& name) {
127   (*dictionary_)[kApVmManager] = name;
128 }
129 
130 static constexpr char kSecureHals[] = "secure_hals";
secure_hals() const131 Result<std::set<SecureHal>> CuttlefishConfig::secure_hals() const {
132   std::set<SecureHal> args_set;
133   for (auto& hal : (*dictionary_)[kSecureHals]) {
134     args_set.insert(CF_EXPECT(ParseSecureHal(hal.asString())));
135   }
136   return args_set;
137 }
set_secure_hals(const std::set<SecureHal> & hals)138 void CuttlefishConfig::set_secure_hals(const std::set<SecureHal>& hals) {
139   Json::Value hals_json_obj(Json::arrayValue);
140   for (const auto& hal : hals) {
141     hals_json_obj.append(ToString(hal));
142   }
143   (*dictionary_)[kSecureHals] = hals_json_obj;
144 }
145 
146 static constexpr char kCrosvmBinary[] = "crosvm_binary";
crosvm_binary() const147 std::string CuttlefishConfig::crosvm_binary() const {
148   return (*dictionary_)[kCrosvmBinary].asString();
149 }
set_crosvm_binary(const std::string & crosvm_binary)150 void CuttlefishConfig::set_crosvm_binary(const std::string& crosvm_binary) {
151   (*dictionary_)[kCrosvmBinary] = crosvm_binary;
152 }
153 
IsCrosvm() const154 bool CuttlefishConfig::IsCrosvm() const {
155   return vm_manager() == VmmMode::kCrosvm;
156 }
157 
158 static constexpr char kGem5DebugFlags[] = "gem5_debug_flags";
gem5_debug_flags() const159 std::string CuttlefishConfig::gem5_debug_flags() const {
160   return (*dictionary_)[kGem5DebugFlags].asString();
161 }
set_gem5_debug_flags(const std::string & gem5_debug_flags)162 void CuttlefishConfig::set_gem5_debug_flags(const std::string& gem5_debug_flags) {
163   (*dictionary_)[kGem5DebugFlags] = gem5_debug_flags;
164 }
165 
166 static constexpr char kWebRTCCertsDir[] = "webrtc_certs_dir";
set_webrtc_certs_dir(const std::string & certs_dir)167 void CuttlefishConfig::set_webrtc_certs_dir(const std::string& certs_dir) {
168   (*dictionary_)[kWebRTCCertsDir] = certs_dir;
169 }
webrtc_certs_dir() const170 std::string CuttlefishConfig::webrtc_certs_dir() const {
171   return (*dictionary_)[kWebRTCCertsDir].asString();
172 }
173 
174 static constexpr char kSigServerPort[] = "webrtc_sig_server_port";
set_sig_server_port(int port)175 void CuttlefishConfig::set_sig_server_port(int port) {
176   (*dictionary_)[kSigServerPort] = port;
177 }
sig_server_port() const178 int CuttlefishConfig::sig_server_port() const {
179   return (*dictionary_)[kSigServerPort].asInt();
180 }
181 
182 static constexpr char kSigServerAddress[] = "webrtc_sig_server_addr";
set_sig_server_address(const std::string & addr)183 void CuttlefishConfig::set_sig_server_address(const std::string& addr) {
184   (*dictionary_)[kSigServerAddress] = addr;
185 }
sig_server_address() const186 std::string CuttlefishConfig::sig_server_address() const {
187   return (*dictionary_)[kSigServerAddress].asString();
188 }
189 
190 static constexpr char kSigServerPath[] = "webrtc_sig_server_path";
set_sig_server_path(const std::string & path)191 void CuttlefishConfig::set_sig_server_path(const std::string& path) {
192   // Don't use SetPath here, it's a URL path not a file system path
193   (*dictionary_)[kSigServerPath] = path;
194 }
sig_server_path() const195 std::string CuttlefishConfig::sig_server_path() const {
196   return (*dictionary_)[kSigServerPath].asString();
197 }
198 
199 static constexpr char kSigServerSecure[] = "webrtc_sig_server_secure";
set_sig_server_secure(bool secure)200 void CuttlefishConfig::set_sig_server_secure(bool secure) {
201   (*dictionary_)[kSigServerSecure] = secure;
202 }
sig_server_secure() const203 bool CuttlefishConfig::sig_server_secure() const {
204   return (*dictionary_)[kSigServerSecure].asBool();
205 }
206 
207 static constexpr char kSigServerStrict[] = "webrtc_sig_server_strict";
set_sig_server_strict(bool strict)208 void CuttlefishConfig::set_sig_server_strict(bool strict) {
209   (*dictionary_)[kSigServerStrict] = strict;
210 }
sig_server_strict() const211 bool CuttlefishConfig::sig_server_strict() const {
212   return (*dictionary_)[kSigServerStrict].asBool();
213 }
214 
215 static constexpr char kHostToolsVersion[] = "host_tools_version";
set_host_tools_version(const std::map<std::string,uint32_t> & versions)216 void CuttlefishConfig::set_host_tools_version(
217     const std::map<std::string, uint32_t>& versions) {
218   Json::Value json(Json::objectValue);
219   for (const auto& [key, value] : versions) {
220     json[key] = value;
221   }
222   (*dictionary_)[kHostToolsVersion] = json;
223 }
host_tools_version() const224 std::map<std::string, uint32_t> CuttlefishConfig::host_tools_version() const {
225   if (!dictionary_->isMember(kHostToolsVersion)) {
226     return {};
227   }
228   std::map<std::string, uint32_t> versions;
229   const auto& elem = (*dictionary_)[kHostToolsVersion];
230   for (auto it = elem.begin(); it != elem.end(); it++) {
231     versions[it.key().asString()] = it->asUInt();
232   }
233   return versions;
234 }
235 
236 static constexpr char kEnableHostUwb[] = "enable_host_uwb";
set_enable_host_uwb(bool enable_host_uwb)237 void CuttlefishConfig::set_enable_host_uwb(bool enable_host_uwb) {
238   (*dictionary_)[kEnableHostUwb] = enable_host_uwb;
239 }
enable_host_uwb() const240 bool CuttlefishConfig::enable_host_uwb() const {
241   return (*dictionary_)[kEnableHostUwb].asBool();
242 }
243 
244 static constexpr char kEnableHostUwbConnector[] = "enable_host_uwb_connector";
set_enable_host_uwb_connector(bool enable_host_uwb)245 void CuttlefishConfig::set_enable_host_uwb_connector(bool enable_host_uwb) {
246   (*dictionary_)[kEnableHostUwbConnector] = enable_host_uwb;
247 }
enable_host_uwb_connector() const248 bool CuttlefishConfig::enable_host_uwb_connector() const {
249   return (*dictionary_)[kEnableHostUwbConnector].asBool();
250 }
251 
252 static constexpr char kPicaUciPort[] = "pica_uci_port";
pica_uci_port() const253 int CuttlefishConfig::pica_uci_port() const {
254   return (*dictionary_)[kPicaUciPort].asInt();
255 }
set_pica_uci_port(int pica_uci_port)256 void CuttlefishConfig::set_pica_uci_port(int pica_uci_port) {
257   (*dictionary_)[kPicaUciPort] = pica_uci_port;
258 }
259 
260 static constexpr char kEnableHostBluetooth[] = "enable_host_bluetooth";
set_enable_host_bluetooth(bool enable_host_bluetooth)261 void CuttlefishConfig::set_enable_host_bluetooth(bool enable_host_bluetooth) {
262   (*dictionary_)[kEnableHostBluetooth] = enable_host_bluetooth;
263 }
enable_host_bluetooth() const264 bool CuttlefishConfig::enable_host_bluetooth() const {
265   return (*dictionary_)[kEnableHostBluetooth].asBool();
266 }
267 
268 static constexpr char kEnableHostBluetoothConnector[] =
269     "enable_host_bluetooth_connector";
set_enable_host_bluetooth_connector(bool enable_host_bluetooth)270 void CuttlefishConfig::set_enable_host_bluetooth_connector(bool enable_host_bluetooth) {
271   (*dictionary_)[kEnableHostBluetoothConnector] = enable_host_bluetooth;
272 }
enable_host_bluetooth_connector() const273 bool CuttlefishConfig::enable_host_bluetooth_connector() const {
274   return (*dictionary_)[kEnableHostBluetoothConnector].asBool();
275 }
276 
277 static constexpr char kEnableAutomotiveProxy[] = "enable_automotive_proxy";
set_enable_automotive_proxy(bool enable_automotive_proxy)278 void CuttlefishConfig::set_enable_automotive_proxy(
279     bool enable_automotive_proxy) {
280   (*dictionary_)[kEnableAutomotiveProxy] = enable_automotive_proxy;
281 }
enable_automotive_proxy() const282 bool CuttlefishConfig::enable_automotive_proxy() const {
283   return (*dictionary_)[kEnableAutomotiveProxy].asBool();
284 }
285 
286 static constexpr char kVhalProxyServerPort[] = "vhal_proxy_server_port";
set_vhal_proxy_server_port(int port)287 void CuttlefishConfig::set_vhal_proxy_server_port(int port) {
288   (*dictionary_)[kVhalProxyServerPort] = port;
289 }
vhal_proxy_server_port() const290 int CuttlefishConfig::vhal_proxy_server_port() const {
291   return (*dictionary_)[kVhalProxyServerPort].asInt();
292 }
293 
294 static constexpr char kEnableHostNfc[] = "enable_host_nfc";
set_enable_host_nfc(bool enable_host_nfc)295 void CuttlefishConfig::set_enable_host_nfc(bool enable_host_nfc) {
296   (*dictionary_)[kEnableHostNfc] = enable_host_nfc;
297 }
enable_host_nfc() const298 bool CuttlefishConfig::enable_host_nfc() const {
299   return (*dictionary_)[kEnableHostNfc].asBool();
300 }
301 
302 static constexpr char kEnableHostNfcConnector[] = "enable_host_nfc_connector";
set_enable_host_nfc_connector(bool enable_host_nfc)303 void CuttlefishConfig::set_enable_host_nfc_connector(bool enable_host_nfc) {
304   (*dictionary_)[kEnableHostNfcConnector] = enable_host_nfc;
305 }
enable_host_nfc_connector() const306 bool CuttlefishConfig::enable_host_nfc_connector() const {
307   return (*dictionary_)[kEnableHostNfcConnector].asBool();
308 }
309 
310 static constexpr char kCasimirInstanceNum[] = "casimir_instance_num";
set_casimir_instance_num(int casimir_instance_num)311 void CuttlefishConfig::set_casimir_instance_num(int casimir_instance_num) {
312   (*dictionary_)[kCasimirInstanceNum] = casimir_instance_num;
313 }
casimir_instance_num() const314 int CuttlefishConfig::casimir_instance_num() const {
315   return (*dictionary_)[kCasimirInstanceNum].asInt();
316 }
317 
318 static constexpr char kCasimirArgs[] = "casimir_args";
set_casimir_args(const std::string & casimir_args)319 void CuttlefishConfig::set_casimir_args(const std::string& casimir_args) {
320   Json::Value args_json_obj(Json::arrayValue);
321   for (const auto& arg : android::base::Split(casimir_args, " ")) {
322     if (!arg.empty()) {
323       args_json_obj.append(arg);
324     }
325   }
326   (*dictionary_)[kCasimirArgs] = args_json_obj;
327 }
casimir_args() const328 std::vector<std::string> CuttlefishConfig::casimir_args() const {
329   std::vector<std::string> casimir_args;
330   for (const Json::Value& arg : (*dictionary_)[kCasimirArgs]) {
331     casimir_args.push_back(arg.asString());
332   }
333   return casimir_args;
334 }
335 
336 static constexpr char kCasimirNciPort[] = "casimir_nci_port";
set_casimir_nci_port(int port)337 void CuttlefishConfig::set_casimir_nci_port(int port) {
338   (*dictionary_)[kCasimirNciPort] = port;
339 }
casimir_nci_port() const340 int CuttlefishConfig::casimir_nci_port() const {
341   return (*dictionary_)[kCasimirNciPort].asInt();
342 }
343 
344 static constexpr char kCasimirRfPort[] = "casimir_rf_port";
set_casimir_rf_port(int port)345 void CuttlefishConfig::set_casimir_rf_port(int port) {
346   (*dictionary_)[kCasimirRfPort] = port;
347 }
casimir_rf_port() const348 int CuttlefishConfig::casimir_rf_port() const {
349   return (*dictionary_)[kCasimirRfPort].asInt();
350 }
351 
352 static constexpr char kNetsimRadios[] = "netsim_radios";
353 
netsim_radio_enable(NetsimRadio flag)354 void CuttlefishConfig::netsim_radio_enable(NetsimRadio flag) {
355   if (dictionary_->isMember(kNetsimRadios)) {
356     // OR the radio to current set of radios
357     (*dictionary_)[kNetsimRadios] = (*dictionary_)[kNetsimRadios].asInt() | flag;
358   } else {
359     (*dictionary_)[kNetsimRadios] = flag;
360   }
361 }
362 
netsim_radio_enabled(NetsimRadio flag) const363 bool CuttlefishConfig::netsim_radio_enabled(NetsimRadio flag) const {
364   return (*dictionary_)[kNetsimRadios].asInt() & flag;
365 }
366 
367 static constexpr char kNetsimInstanceNum[] = "netsim_instance_num";
netsim_instance_num() const368 int CuttlefishConfig::netsim_instance_num() const {
369   return (*dictionary_)[kNetsimInstanceNum].asInt();
370 }
set_netsim_instance_num(int netsim_instance_num)371 void CuttlefishConfig::set_netsim_instance_num(int netsim_instance_num) {
372   (*dictionary_)[kNetsimInstanceNum] = netsim_instance_num;
373 }
374 
375 static constexpr char kNetsimConnectorInstanceNum[] =
376     "netsim_connector_instance_num";
netsim_connector_instance_num() const377 int CuttlefishConfig::netsim_connector_instance_num() const {
378   return (*dictionary_)[kNetsimConnectorInstanceNum].asInt();
379 }
set_netsim_connector_instance_num(int netsim_instance_num)380 void CuttlefishConfig::set_netsim_connector_instance_num(
381     int netsim_instance_num) {
382   (*dictionary_)[kNetsimConnectorInstanceNum] = netsim_instance_num;
383 }
384 
385 static constexpr char kNetsimArgs[] = "netsim_args";
set_netsim_args(const std::string & netsim_args)386 void CuttlefishConfig::set_netsim_args(const std::string& netsim_args) {
387   Json::Value args_json_obj(Json::arrayValue);
388   for (const auto& arg : android::base::Tokenize(netsim_args, " ")) {
389     args_json_obj.append(arg);
390   }
391   (*dictionary_)[kNetsimArgs] = args_json_obj;
392 }
netsim_args() const393 std::vector<std::string> CuttlefishConfig::netsim_args() const {
394   std::vector<std::string> netsim_args;
395   for (const Json::Value& arg : (*dictionary_)[kNetsimArgs]) {
396     netsim_args.push_back(arg.asString());
397   }
398   return netsim_args;
399 }
400 
401 static constexpr char kEnableMetrics[] = "enable_metrics";
set_enable_metrics(std::string enable_metrics)402 void CuttlefishConfig::set_enable_metrics(std::string enable_metrics) {
403   (*dictionary_)[kEnableMetrics] =
404       static_cast<int>(cuttlefish::CuttlefishConfig::Answer::kUnknown);
405   if (!enable_metrics.empty()) {
406     switch (enable_metrics.at(0)) {
407       case 'y':
408       case 'Y':
409         (*dictionary_)[kEnableMetrics] =
410             static_cast<int>(cuttlefish::CuttlefishConfig::Answer::kYes);
411         break;
412       case 'n':
413       case 'N':
414         (*dictionary_)[kEnableMetrics] =
415             static_cast<int>(cuttlefish::CuttlefishConfig::Answer::kNo);
416         break;
417     }
418   }
419 }
420 
421 // validate the casting and conversion from json configs to
422 // CuttlefishConfig::Answer class
IsValidMetricsConfigs(int value)423 bool IsValidMetricsConfigs(int value) {
424   return value == static_cast<int>(CuttlefishConfig::Answer::kUnknown) ||
425          value == static_cast<int>(CuttlefishConfig::Answer::kNo) ||
426          value == static_cast<int>(CuttlefishConfig::Answer::kYes);
427 }
428 
enable_metrics() const429 CuttlefishConfig::Answer CuttlefishConfig::enable_metrics() const {
430   int value = (*dictionary_)[kEnableMetrics].asInt();
431   if (!IsValidMetricsConfigs(value)) {
432     LOG(ERROR) << "Invalid integer value for Answer enum";
433     return static_cast<Answer>(CuttlefishConfig::Answer::kUnknown);
434   }
435   return static_cast<Answer>(value);
436 }
437 
438 static constexpr char kMetricsBinary[] = "metrics_binary";
set_metrics_binary(const std::string & metrics_binary)439 void CuttlefishConfig::set_metrics_binary(const std::string& metrics_binary) {
440   (*dictionary_)[kMetricsBinary] = metrics_binary;
441 }
metrics_binary() const442 std::string CuttlefishConfig::metrics_binary() const {
443   return (*dictionary_)[kMetricsBinary].asString();
444 }
445 
446 static constexpr char kExtraKernelCmdline[] = "extra_kernel_cmdline";
set_extra_kernel_cmdline(const std::string & extra_cmdline)447 void CuttlefishConfig::set_extra_kernel_cmdline(
448     const std::string& extra_cmdline) {
449   Json::Value args_json_obj(Json::arrayValue);
450   for (const auto& arg : android::base::Split(extra_cmdline, " ")) {
451     args_json_obj.append(arg);
452   }
453   (*dictionary_)[kExtraKernelCmdline] = args_json_obj;
454 }
extra_kernel_cmdline() const455 std::vector<std::string> CuttlefishConfig::extra_kernel_cmdline() const {
456   std::vector<std::string> cmdline;
457   for (const Json::Value& arg : (*dictionary_)[kExtraKernelCmdline]) {
458     cmdline.push_back(arg.asString());
459   }
460   return cmdline;
461 }
462 
463 static constexpr char kVirtioMac80211Hwsim[] = "virtio_mac80211_hwsim";
set_virtio_mac80211_hwsim(bool virtio_mac80211_hwsim)464 void CuttlefishConfig::set_virtio_mac80211_hwsim(bool virtio_mac80211_hwsim) {
465   (*dictionary_)[kVirtioMac80211Hwsim] = virtio_mac80211_hwsim;
466 }
virtio_mac80211_hwsim() const467 bool CuttlefishConfig::virtio_mac80211_hwsim() const {
468   return (*dictionary_)[kVirtioMac80211Hwsim].asBool();
469 }
470 
471 static constexpr char kApRootfsImage[] = "ap_rootfs_image";
ap_rootfs_image() const472 std::string CuttlefishConfig::ap_rootfs_image() const {
473   return (*dictionary_)[kApRootfsImage].asString();
474 }
set_ap_rootfs_image(const std::string & ap_rootfs_image)475 void CuttlefishConfig::set_ap_rootfs_image(const std::string& ap_rootfs_image) {
476   (*dictionary_)[kApRootfsImage] = ap_rootfs_image;
477 }
478 
479 static constexpr char kApKernelImage[] = "ap_kernel_image";
ap_kernel_image() const480 std::string CuttlefishConfig::ap_kernel_image() const {
481   return (*dictionary_)[kApKernelImage].asString();
482 }
set_ap_kernel_image(const std::string & ap_kernel_image)483 void CuttlefishConfig::set_ap_kernel_image(const std::string& ap_kernel_image) {
484   (*dictionary_)[kApKernelImage] = ap_kernel_image;
485 }
486 
487 static constexpr char kRootcanalArgs[] = "rootcanal_args";
set_rootcanal_args(const std::string & rootcanal_args)488 void CuttlefishConfig::set_rootcanal_args(const std::string& rootcanal_args) {
489   Json::Value args_json_obj(Json::arrayValue);
490   for (const auto& arg : android::base::Split(rootcanal_args, " ")) {
491     args_json_obj.append(arg);
492   }
493   (*dictionary_)[kRootcanalArgs] = args_json_obj;
494 }
rootcanal_args() const495 std::vector<std::string> CuttlefishConfig::rootcanal_args() const {
496   std::vector<std::string> rootcanal_args;
497   for (const Json::Value& arg : (*dictionary_)[kRootcanalArgs]) {
498     rootcanal_args.push_back(arg.asString());
499   }
500   return rootcanal_args;
501 }
502 
503 static constexpr char kRootcanalHciPort[] = "rootcanal_hci_port";
rootcanal_hci_port() const504 int CuttlefishConfig::rootcanal_hci_port() const {
505   return (*dictionary_)[kRootcanalHciPort].asInt();
506 }
set_rootcanal_hci_port(int rootcanal_hci_port)507 void CuttlefishConfig::set_rootcanal_hci_port(int rootcanal_hci_port) {
508   (*dictionary_)[kRootcanalHciPort] = rootcanal_hci_port;
509 }
510 
511 static constexpr char kRootcanalLinkPort[] = "rootcanal_link_port";
rootcanal_link_port() const512 int CuttlefishConfig::rootcanal_link_port() const {
513   return (*dictionary_)[kRootcanalLinkPort].asInt();
514 }
set_rootcanal_link_port(int rootcanal_link_port)515 void CuttlefishConfig::set_rootcanal_link_port(int rootcanal_link_port) {
516   (*dictionary_)[kRootcanalLinkPort] = rootcanal_link_port;
517 }
518 
519 static constexpr char kRootcanalLinkBlePort[] = "rootcanal_link_ble_port";
rootcanal_link_ble_port() const520 int CuttlefishConfig::rootcanal_link_ble_port() const {
521   return (*dictionary_)[kRootcanalLinkBlePort].asInt();
522 }
set_rootcanal_link_ble_port(int rootcanal_link_ble_port)523 void CuttlefishConfig::set_rootcanal_link_ble_port(
524     int rootcanal_link_ble_port) {
525   (*dictionary_)[kRootcanalLinkBlePort] = rootcanal_link_ble_port;
526 }
527 
528 static constexpr char kRootcanalTestPort[] = "rootcanal_test_port";
rootcanal_test_port() const529 int CuttlefishConfig::rootcanal_test_port() const {
530   return (*dictionary_)[kRootcanalTestPort].asInt();
531 }
set_rootcanal_test_port(int rootcanal_test_port)532 void CuttlefishConfig::set_rootcanal_test_port(int rootcanal_test_port) {
533   (*dictionary_)[kRootcanalTestPort] = rootcanal_test_port;
534 }
535 
536 static constexpr char kSnapshotPath[] = "snapshot_path";
snapshot_path() const537 std::string CuttlefishConfig::snapshot_path() const {
538   return (*dictionary_)[kSnapshotPath].asString();
539 }
set_snapshot_path(const std::string & snapshot_path)540 void CuttlefishConfig::set_snapshot_path(const std::string& snapshot_path) {
541   (*dictionary_)[kSnapshotPath] = snapshot_path;
542 }
543 
544 static constexpr char kStracedExecutables[] = "straced_host_executables";
set_straced_host_executables(const std::set<std::string> & straced_host_executables)545 void CuttlefishConfig::set_straced_host_executables(
546     const std::set<std::string>& straced_host_executables) {
547   Json::Value args_json_obj(Json::arrayValue);
548   for (const auto& arg : straced_host_executables) {
549     args_json_obj.append(arg);
550   }
551   (*dictionary_)[kStracedExecutables] = args_json_obj;
552 }
straced_host_executables() const553 std::set<std::string> CuttlefishConfig::straced_host_executables() const {
554   std::set<std::string> straced_host_executables;
555   for (const Json::Value& arg : (*dictionary_)[kStracedExecutables]) {
556     straced_host_executables.insert(arg.asString());
557   }
558   return straced_host_executables;
559 }
560 
BuildConfigImpl(const std::string & path)561 /*static*/ CuttlefishConfig* CuttlefishConfig::BuildConfigImpl(
562     const std::string& path) {
563   auto ret = new CuttlefishConfig();
564   if (ret) {
565     auto loaded = ret->LoadFromFile(path.c_str());
566     if (!loaded) {
567       delete ret;
568       return nullptr;
569     }
570   }
571   return ret;
572 }
573 
574 /*static*/ std::unique_ptr<const CuttlefishConfig>
GetFromFile(const std::string & path)575 CuttlefishConfig::GetFromFile(const std::string& path) {
576   return std::unique_ptr<const CuttlefishConfig>(BuildConfigImpl(path));
577 }
578 
579 // Creates the (initially empty) config object and populates it with values from
580 // the config file if the CUTTLEFISH_CONFIG_FILE env variable is present.
581 // Returns nullptr if there was an error loading from file
Get()582 /*static*/ const CuttlefishConfig* CuttlefishConfig::Get() {
583   auto config_file_path =
584       StringFromEnv(kCuttlefishConfigEnvVarName, GetGlobalConfigFileLink());
585   static std::shared_ptr<CuttlefishConfig> config(
586       BuildConfigImpl(config_file_path));
587   return config.get();
588 }
589 
ConfigExists()590 /*static*/ bool CuttlefishConfig::ConfigExists() {
591   auto config_file_path = StringFromEnv(kCuttlefishConfigEnvVarName,
592                                         GetGlobalConfigFileLink());
593   auto real_file_path = AbsolutePath(config_file_path.c_str());
594   return FileExists(real_file_path);
595 }
596 
CuttlefishConfig()597 CuttlefishConfig::CuttlefishConfig() : dictionary_(new Json::Value()) {}
598 // Can't use '= default' on the header because the compiler complains of
599 // Json::Value being an incomplete type
600 CuttlefishConfig::~CuttlefishConfig() = default;
601 
602 CuttlefishConfig::CuttlefishConfig(CuttlefishConfig&&) = default;
603 CuttlefishConfig& CuttlefishConfig::operator=(CuttlefishConfig&&) = default;
604 
LoadFromFile(const char * file)605 bool CuttlefishConfig::LoadFromFile(const char* file) {
606   auto real_file_path = AbsolutePath(file);
607   if (real_file_path.empty()) {
608     LOG(ERROR) << "Could not get real path for file " << file;
609     return false;
610   }
611   Json::CharReaderBuilder builder;
612   std::ifstream ifs(real_file_path);
613   std::string errorMessage;
614   if (!Json::parseFromStream(builder, ifs, dictionary_.get(), &errorMessage)) {
615     LOG(ERROR) << "Could not read config file " << file << ": " << errorMessage;
616     return false;
617   }
618   return true;
619 }
SaveToFile(const std::string & file) const620 bool CuttlefishConfig::SaveToFile(const std::string& file) const {
621   std::ofstream ofs(file);
622   if (!ofs.is_open()) {
623     LOG(ERROR) << "Unable to write to file " << file;
624     return false;
625   }
626   ofs << *dictionary_;
627   return !ofs.fail();
628 }
629 
instances_dir() const630 std::string CuttlefishConfig::instances_dir() const {
631   return AbsolutePath(root_dir() + "/instances");
632 }
633 
InstancesPath(const std::string & file_name) const634 std::string CuttlefishConfig::InstancesPath(
635     const std::string& file_name) const {
636   return AbsolutePath(instances_dir() + "/" + file_name);
637 }
638 
assembly_dir() const639 std::string CuttlefishConfig::assembly_dir() const {
640   return AbsolutePath(root_dir() + "/assembly");
641 }
642 
AssemblyPath(const std::string & file_name) const643 std::string CuttlefishConfig::AssemblyPath(
644     const std::string& file_name) const {
645   return AbsolutePath(assembly_dir() + "/" + file_name);
646 }
647 
648 static constexpr char kInstancesUdsDir[] = "instances_uds_dir";
set_instances_uds_dir(const std::string & dir)649 void CuttlefishConfig::set_instances_uds_dir(const std::string& dir) {
650   (*dictionary_)[kInstancesUdsDir] = dir;
651 }
instances_uds_dir() const652 std::string CuttlefishConfig::instances_uds_dir() const {
653   return (*dictionary_)[kInstancesUdsDir].asString();
654 }
655 
InstancesUdsPath(const std::string & file_name) const656 std::string CuttlefishConfig::InstancesUdsPath(
657     const std::string& file_name) const {
658   return AbsolutePath(instances_uds_dir() + "/" + file_name);
659 }
660 
environments_dir() const661 std::string CuttlefishConfig::environments_dir() const {
662   return AbsolutePath(root_dir() + "/environments");
663 }
664 
EnvironmentsPath(const std::string & file_name) const665 std::string CuttlefishConfig::EnvironmentsPath(
666     const std::string& file_name) const {
667   return AbsolutePath(environments_dir() + "/" + file_name);
668 }
669 
670 static constexpr char kEnvironmentsUdsDir[] = "environments_uds_dir";
set_environments_uds_dir(const std::string & dir)671 void CuttlefishConfig::set_environments_uds_dir(const std::string& dir) {
672   (*dictionary_)[kEnvironmentsUdsDir] = dir;
673 }
environments_uds_dir() const674 std::string CuttlefishConfig::environments_uds_dir() const {
675   return (*dictionary_)[kEnvironmentsUdsDir].asString();
676 }
677 
EnvironmentsUdsPath(const std::string & file_name) const678 std::string CuttlefishConfig::EnvironmentsUdsPath(
679     const std::string& file_name) const {
680   return AbsolutePath(environments_uds_dir() + "/" + file_name);
681 }
682 
ForInstance(int num)683 CuttlefishConfig::MutableInstanceSpecific CuttlefishConfig::ForInstance(int num) {
684   return MutableInstanceSpecific(this, std::to_string(num));
685 }
686 
ForInstance(int num) const687 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstance(int num) const {
688   return InstanceSpecific(this, std::to_string(num));
689 }
690 
ForInstanceName(const std::string & name) const691 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForInstanceName(
692     const std::string& name) const {
693   return ForInstance(InstanceFromString(name));
694 }
695 
ForDefaultInstance() const696 CuttlefishConfig::InstanceSpecific CuttlefishConfig::ForDefaultInstance() const {
697   return ForInstance(GetInstance());
698 }
699 
Instances() const700 std::vector<CuttlefishConfig::InstanceSpecific> CuttlefishConfig::Instances() const {
701   const auto& json = (*dictionary_)[kInstances];
702   std::vector<CuttlefishConfig::InstanceSpecific> instances;
703   for (const auto& name : json.getMemberNames()) {
704     instances.push_back(CuttlefishConfig::InstanceSpecific(this, name));
705   }
706   return instances;
707 }
708 
instance_dirs() const709 std::vector<std::string> CuttlefishConfig::instance_dirs() const {
710   std::vector<std::string> result;
711   for (const auto& instance : Instances()) {
712     result.push_back(instance.instance_dir());
713     result.push_back(instance.instance_uds_dir());
714   }
715   return result;
716 }
717 
718 static constexpr char kInstanceNames[] = "instance_names";
set_instance_names(const std::vector<std::string> & instance_names)719 void CuttlefishConfig::set_instance_names(
720     const std::vector<std::string>& instance_names) {
721   Json::Value args_json_obj(Json::arrayValue);
722   for (const auto& name : instance_names) {
723     args_json_obj.append(name);
724   }
725   (*dictionary_)[kInstanceNames] = args_json_obj;
726 }
instance_names() const727 std::vector<std::string> CuttlefishConfig::instance_names() const {
728   // NOTE: The structure of this field needs to remain stable, since
729   // cvd_server may call this on config JSON files from various builds.
730   //
731   // This info is duplicated into its own field here so it is simpler
732   // to keep stable, rather than parsing from Instances()::instance_name.
733   //
734   // Any non-stable changes must be accompanied by an uprev to the
735   // cvd_server major version.
736   std::vector<std::string> names;
737   for (const Json::Value& name : (*dictionary_)[kInstanceNames]) {
738     names.push_back(name.asString());
739   }
740   return names;
741 }
742 
ForEnvironment(const std::string & envName)743 CuttlefishConfig::MutableEnvironmentSpecific CuttlefishConfig::ForEnvironment(
744     const std::string& envName) {
745   return MutableEnvironmentSpecific(this, envName);
746 }
747 
ForEnvironment(const std::string & envName) const748 CuttlefishConfig::EnvironmentSpecific CuttlefishConfig::ForEnvironment(
749     const std::string& envName) const {
750   return EnvironmentSpecific(this, envName);
751 }
752 
753 CuttlefishConfig::MutableEnvironmentSpecific
ForDefaultEnvironment()754 CuttlefishConfig::ForDefaultEnvironment() {
755   return MutableEnvironmentSpecific(this,
756                                     ForDefaultInstance().environment_name());
757 }
758 
ForDefaultEnvironment() const759 CuttlefishConfig::EnvironmentSpecific CuttlefishConfig::ForDefaultEnvironment()
760     const {
761   return EnvironmentSpecific(this, ForDefaultInstance().environment_name());
762 }
763 
environment_dirs() const764 std::vector<std::string> CuttlefishConfig::environment_dirs() const {
765   auto environment = ForDefaultEnvironment();
766 
767   std::vector<std::string> result;
768 
769   result.push_back(environment.environment_dir());
770   result.push_back(environment.environment_uds_dir());
771 
772   return result;
773 }
774 
775 }  // namespace cuttlefish
776