• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "host/commands/assemble_cvd/flags.h"
2 
3 #include <android-base/logging.h>
4 #include <android-base/parseint.h>
5 #include <android-base/strings.h>
6 #include <gflags/gflags.h>
7 #include <json/json.h>
8 #include <json/writer.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 
12 #include <algorithm>
13 #include <array>
14 #include <fstream>
15 #include <iostream>
16 #include <optional>
17 #include <regex>
18 #include <set>
19 #include <sstream>
20 #include <unordered_map>
21 
22 #include <fruit/fruit.h>
23 
24 #include "common/libs/utils/environment.h"
25 #include "common/libs/utils/files.h"
26 #include "common/libs/utils/flag_parser.h"
27 #include "host/commands/assemble_cvd/alloc.h"
28 #include "host/commands/assemble_cvd/boot_config.h"
29 #include "host/commands/assemble_cvd/disk_flags.h"
30 #include "host/libs/config/config_flag.h"
31 #include "host/libs/config/host_tools_version.h"
32 #include "host/libs/graphics_detector/graphics_detector.h"
33 #include "host/libs/vm_manager/crosvm_manager.h"
34 #include "host/libs/vm_manager/gem5_manager.h"
35 #include "host/libs/vm_manager/qemu_manager.h"
36 #include "host/libs/vm_manager/vm_manager.h"
37 
38 using cuttlefish::DefaultHostArtifactsPath;
39 using cuttlefish::HostBinaryPath;
40 using cuttlefish::StringFromEnv;
41 using cuttlefish::vm_manager::CrosvmManager;
42 using google::FlagSettingMode::SET_FLAGS_DEFAULT;
43 using google::FlagSettingMode::SET_FLAGS_VALUE;
44 
45 DEFINE_int32(cpus, 2, "Virtual CPU count.");
46 DEFINE_string(data_policy, "use_existing", "How to handle userdata partition."
47             " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
48             "'always_create'.");
49 DEFINE_int32(blank_data_image_mb, 0,
50              "The size of the blank data image to generate, MB.");
51 DEFINE_int32(gdb_port, 0,
52              "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The"
53              "kernel must have been built with CONFIG_RANDOMIZE_BASE "
54              "disabled.");
55 
56 constexpr const char kDisplayHelp[] =
57     "Comma separated key=value pairs of display properties. Supported "
58     "properties:\n"
59     " 'width': required, width of the display in pixels\n"
60     " 'height': required, height of the display in pixels\n"
61     " 'dpi': optional, default 320, density of the display\n"
62     " 'refresh_rate_hz': optional, default 60, display refresh rate in Hertz\n"
63     ". Example usage: \n"
64     "--display0=width=1280,height=720\n"
65     "--display1=width=1440,height=900,dpi=480,refresh_rate_hz=30\n";
66 
67 // TODO(b/192495477): combine these into a single repeatable '--display' flag
68 // when assemble_cvd switches to using the new flag parsing library.
69 DEFINE_string(display0, "", kDisplayHelp);
70 DEFINE_string(display1, "", kDisplayHelp);
71 DEFINE_string(display2, "", kDisplayHelp);
72 DEFINE_string(display3, "", kDisplayHelp);
73 
74 // TODO(b/171305898): mark these as deprecated after multi-display is fully
75 // enabled.
76 DEFINE_int32(x_res, 0, "Width of the screen in pixels");
77 DEFINE_int32(y_res, 0, "Height of the screen in pixels");
78 DEFINE_int32(dpi, 0, "Pixels per inch for the screen");
79 DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
80 DEFINE_string(kernel_path, "",
81               "Path to the kernel. Overrides the one from the boot image");
82 DEFINE_string(initramfs_path, "", "Path to the initramfs");
83 DEFINE_string(extra_kernel_cmdline, "",
84               "Additional flags to put on the kernel command line");
85 DEFINE_string(extra_bootconfig_args, "",
86               "Space-separated list of extra bootconfig args. "
87               "Note: overwriting an existing bootconfig argument "
88               "requires ':=' instead of '='.");
89 DEFINE_bool(guest_enforce_security, true,
90             "Whether to run in enforcing mode (non permissive).");
91 DEFINE_int32(memory_mb, 0, "Total amount of memory available for guest, MB.");
92 DEFINE_string(serial_number, cuttlefish::ForCurrentInstance("CUTTLEFISHCVD"),
93               "Serial number to use for the device");
94 DEFINE_bool(use_random_serial, false,
95             "Whether to use random serial for the device.");
96 DEFINE_string(vm_manager, "",
97               "What virtual machine manager to use, one of {qemu_cli, crosvm}");
98 DEFINE_string(gpu_mode, cuttlefish::kGpuModeAuto,
99               "What gpu configuration to use, one of {auto, drm_virgl, "
100               "gfxstream, guest_swiftshader}");
101 DEFINE_string(hwcomposer, cuttlefish::kHwComposerAuto,
102               "What hardware composer to use, one of {auto, drm, ranchu} ");
103 DEFINE_string(gpu_capture_binary, "",
104               "Path to the GPU capture binary to use when capturing GPU traces"
105               "(ngfx, renderdoc, etc)");
106 DEFINE_bool(enable_gpu_udmabuf,
107             false,
108             "Use the udmabuf driver for zero-copy virtio-gpu");
109 
110 DEFINE_bool(enable_gpu_angle,
111             false,
112             "Use ANGLE to provide GLES implementation (always true for"
113             " guest_swiftshader");
114 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
115             " host kernel. This is only used during transition of our clients."
116             " Will be deprecated soon.");
117 
118 DEFINE_bool(use_allocd, false,
119             "Acquire static resources from the resource allocator daemon.");
120 DEFINE_bool(enable_minimal_mode, false,
121             "Only enable the minimum features to boot a cuttlefish device and "
122             "support minimal UI interactions.\nNote: Currently only supports "
123             "handheld/phone targets");
124 DEFINE_bool(pause_in_bootloader, false,
125             "Stop the bootflow in u-boot. You can continue the boot by connecting "
126             "to the device console and typing in \"boot\".");
127 DEFINE_bool(enable_host_bluetooth, true,
128             "Enable the root-canal which is Bluetooth emulator in the host.");
129 
130 DEFINE_string(bluetooth_controller_properties_file,
131               "etc/rootcanal/data/controller_properties.json",
132               "The configuartion file path for root-canal which is a Bluetooth "
133               "emulator.");
134 DEFINE_string(
135     bluetooth_default_commands_file, "etc/rootcanal/data/default_commands",
136     "The default commands which root-canal executes when it launches.");
137 
138 /**
139  *
140  * crosvm sandbox feature requires /var/empty and seccomp directory
141  *
142  * --enable-sandbox: will enforce the sandbox feature
143  *                   failing to meet the requirements result in assembly_cvd termination
144  *
145  * --enable-sandbox=no, etc: will disable sandbox
146  *
147  * no option given: it is enabled if /var/empty exists and an empty directory
148  *                             or if it does not exist and can be created
149  *
150  * if seccomp dir doesn't exist, assembly_cvd will terminate
151  *
152  * See SetDefaultFlagsForCrosvm()
153  *
154  */
155 DEFINE_bool(enable_sandbox,
156             false,
157             "Enable crosvm sandbox. Use this when you are sure about what you are doing.");
158 
159 static const std::string kSeccompDir =
160     std::string("usr/share/crosvm/") + cuttlefish::HostArchStr() + "-linux-gnu/seccomp";
161 DEFINE_string(seccomp_policy_dir, DefaultHostArtifactsPath(kSeccompDir),
162               "With sandbox'ed crosvm, overrieds the security comp policy directory");
163 
164 DEFINE_bool(start_webrtc, false, "Whether to start the webrtc process.");
165 
166 DEFINE_string(
167         webrtc_assets_dir, DefaultHostArtifactsPath("usr/share/webrtc/assets"),
168         "[Experimental] Path to WebRTC webpage assets.");
169 
170 DEFINE_string(
171         webrtc_certs_dir, DefaultHostArtifactsPath("usr/share/webrtc/certs"),
172         "[Experimental] Path to WebRTC certificates directory.");
173 
174 DEFINE_string(
175         webrtc_public_ip,
176         "0.0.0.0",
177         "[Deprecated] Ignored, webrtc can figure out its IP address");
178 
179 DEFINE_bool(
180         webrtc_enable_adb_websocket,
181         false,
182         "[Experimental] If enabled, exposes local adb service through a websocket.");
183 
184 static constexpr auto HOST_OPERATOR_SOCKET_PATH = "/run/cuttlefish/operator";
185 
186 DEFINE_bool(
187     // The actual default for this flag is set with SetCommandLineOption() in
188     // GetKernelConfigsAndSetDefaults() at the end of this file.
189     start_webrtc_sig_server, true,
190     "Whether to start the webrtc signaling server. This option only applies to "
191     "the first instance, if multiple instances are launched they'll share the "
192     "same signaling server, which is owned by the first one.");
193 
194 DEFINE_string(webrtc_sig_server_addr, "",
195               "The address of the webrtc signaling server.");
196 
197 DEFINE_int32(
198     webrtc_sig_server_port, 443,
199     "The port of the signaling server if started outside of this launch. If "
200     "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
201     "this parameter is ignored.");
202 
203 // TODO (jemoreira): We need a much bigger range to reliably support several
204 // simultaneous connections.
205 DEFINE_string(tcp_port_range, "15550:15558",
206               "The minimum and maximum TCP port numbers to allocate for ICE "
207               "candidates as 'min:max'. To use any port just specify '0:0'");
208 
209 DEFINE_string(udp_port_range, "15550:15558",
210               "The minimum and maximum UDP port numbers to allocate for ICE "
211               "candidates as 'min:max'. To use any port just specify '0:0'");
212 
213 DEFINE_string(webrtc_sig_server_path, "/register_device",
214               "The path section of the URL where the device should be "
215               "registered with the signaling server.");
216 
217 DEFINE_bool(webrtc_sig_server_secure, true,
218             "Whether the WebRTC signaling server uses secure protocols (WSS vs WS).");
219 
220 DEFINE_bool(verify_sig_server_certificate, false,
221             "Whether to verify the signaling server's certificate with a "
222             "trusted signing authority (Disallow self signed certificates). "
223             "This is ignored if an insecure server is configured.");
224 
225 DEFINE_string(sig_server_headers_file, "",
226               "Path to a file containing HTTP headers to be included in the "
227               "connection to the signaling server. Each header should be on a "
228               "line by itself in the form <name>: <value>");
229 
230 DEFINE_string(
231     webrtc_device_id, "cvd-{num}",
232     "The for the device to register with the signaling server. Every "
233     "appearance of the substring '{num}' in the device id will be substituted "
234     "with the instance number to support multiple instances");
235 
236 DEFINE_string(uuid, cuttlefish::ForCurrentInstance(cuttlefish::kDefaultUuidPrefix),
237               "UUID to use for the device. Random if not specified");
238 DEFINE_bool(daemon, false,
239             "Run cuttlefish in background, the launcher exits on boot "
240             "completed/failed");
241 
242 DEFINE_string(setupwizard_mode, "DISABLED",
243             "One of DISABLED,OPTIONAL,REQUIRED");
244 
245 DEFINE_string(qemu_binary_dir, "/usr/bin",
246               "Path to the directory containing the qemu binary to use");
247 DEFINE_string(crosvm_binary, HostBinaryPath("crosvm"),
248               "The Crosvm binary to use");
249 DEFINE_string(gem5_binary_dir, HostBinaryPath("gem5"),
250               "Path to the gem5 build tree root");
251 DEFINE_bool(restart_subprocesses, true, "Restart any crashed host process");
252 DEFINE_bool(enable_vehicle_hal_grpc_server, true, "Enables the vehicle HAL "
253             "emulation gRPC server on the host");
254 DEFINE_string(bootloader, "", "Bootloader binary path");
255 DEFINE_string(boot_slot, "", "Force booting into the given slot. If empty, "
256              "the slot will be chosen based on the misc partition if using a "
257              "bootloader. It will default to 'a' if empty and not using a "
258              "bootloader.");
259 DEFINE_int32(num_instances, 1, "Number of Android guests to launch");
260 DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage "
261             "statistics for metrics collection and analysis.");
262 DEFINE_string(ril_dns, "8.8.8.8", "DNS address of mobile network (RIL)");
263 DEFINE_bool(kgdb, false, "Configure the virtual device for debugging the kernel "
264                          "with kgdb/kdb. The kernel must have been built with "
265                          "kgdb support, and serial console must be enabled.");
266 
267 DEFINE_bool(start_gnss_proxy, false, "Whether to start the gnss proxy.");
268 
269 DEFINE_string(gnss_file_path, "",
270               "Local gnss file path for the gnss proxy");
271 
272 // by default, this modem-simulator is disabled
273 DEFINE_bool(enable_modem_simulator, true,
274             "Enable the modem simulator to process RILD AT commands");
275 // modem_simulator_sim_type=2 for test CtsCarrierApiTestCases
276 DEFINE_int32(modem_simulator_sim_type, 1,
277              "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
278 
279 DEFINE_bool(console, false, "Enable the serial console");
280 
281 DEFINE_bool(vhost_net, false, "Enable vhost acceleration of networking");
282 
283 DEFINE_string(
284     vhost_user_mac80211_hwsim, "",
285     "Unix socket path for vhost-user of mac80211_hwsim, typically served by "
286     "wmediumd. You can set this when using an external wmediumd instance.");
287 DEFINE_string(wmediumd_config, "",
288               "Path to the wmediumd config file. When missing, the default "
289               "configuration is used which adds MAC addresses for up to 16 "
290               "cuttlefish instances including AP.");
291 DEFINE_string(ap_rootfs_image,
292               DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs"),
293               "rootfs image for AP instance");
294 DEFINE_string(ap_kernel_image,
295               DefaultHostArtifactsPath("etc/openwrt/images/kernel_for_openwrt"),
296               "kernel image for AP instance");
297 
298 DEFINE_bool(record_screen, false, "Enable screen recording. "
299                                   "Requires --start_webrtc");
300 
301 DEFINE_bool(smt, false, "Enable simultaneous multithreading (SMT/HT)");
302 
303 DEFINE_int32(vsock_guest_cid,
304              cuttlefish::GetDefaultVsockCid(),
305              "vsock_guest_cid is used to determine the guest vsock cid as well as all the ports"
306              "of all vsock servers such as tombstone or modem simulator(s)."
307              "The vsock ports and guest vsock cid are a function of vsock_guest_cid and instance number."
308              "An instance number of i th instance is determined by --num_instances=N and --base_instance_num=B"
309              "The instance number of i th instance is B + i where i in [0, N-1] and B >= 1."
310              "See --num_instances, and --base_instance_num for more information"
311              "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. Otherwise,"
312              "the guest vsock cid is 2 + instance number, which is 2 + (B + i)."
313              "If --vsock_guest_cid is not given, each vsock server port number for i th instance is"
314              "base + instance number - 1. vsock_guest_cid is by default B + i + 2."
315              "Thus, by default, each port is base + vsock_guest_cid - 3."
316              "The same formula holds when --vsock_guest_cid=C is given, for algorithm's sake."
317              "Each vsock server port number is base + C - 3.");
318 
319 DEFINE_string(secure_hals, "keymint,gatekeeper",
320               "Which HALs to use enable host security features for. Supports "
321               "keymint and gatekeeper at the moment.");
322 
323 DEFINE_bool(use_sdcard, true, "Create blank SD-Card image and expose to guest");
324 
325 DEFINE_bool(protected_vm, false, "Boot in Protected VM mode");
326 
327 DEFINE_bool(enable_audio, cuttlefish::HostArch() != cuttlefish::Arch::Arm64,
328             "Whether to play or capture audio");
329 
330 DEFINE_uint32(camera_server_port, 0, "camera vsock port");
331 
332 DEFINE_string(userdata_format, "f2fs", "The userdata filesystem format");
333 
334 DECLARE_string(assembly_dir);
335 DECLARE_string(boot_image);
336 DECLARE_string(system_image_dir);
337 
338 namespace cuttlefish {
339 using vm_manager::QemuManager;
340 using vm_manager::Gem5Manager;
341 using vm_manager::GetVmManager;
342 
343 namespace {
344 
ParsePortRange(const std::string & flag)345 std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
346   static const std::regex rgx("[0-9]+:[0-9]+");
347   CHECK(std::regex_match(flag, rgx))
348       << "Port range flag has invalid value: " << flag;
349   std::pair<uint16_t, uint16_t> port_range;
350   std::stringstream ss(flag);
351   char c;
352   ss >> port_range.first;
353   ss.read(&c, 1);
354   ss >> port_range.second;
355   return port_range;
356 }
357 
StrForInstance(const std::string & prefix,int num)358 std::string StrForInstance(const std::string& prefix, int num) {
359   std::ostringstream stream;
360   stream << prefix << std::setfill('0') << std::setw(2) << num;
361   return stream.str();
362 }
363 
ParseDisplayConfig(const std::string & flag)364 std::optional<CuttlefishConfig::DisplayConfig> ParseDisplayConfig(
365     const std::string& flag) {
366   if (flag.empty()) {
367     return std::nullopt;
368   }
369 
370   std::unordered_map<std::string, std::string> props;
371 
372   const std::vector<std::string> pairs = android::base::Split(flag, ",");
373   for (const std::string& pair : pairs) {
374     const std::vector<std::string> keyvalue = android::base::Split(pair, "=");
375     CHECK_EQ(2, keyvalue.size()) << "Invalid display: " << flag;
376 
377     const std::string& prop_key = keyvalue[0];
378     const std::string& prop_val = keyvalue[1];
379     props[prop_key] = prop_val;
380   }
381 
382   CHECK(props.find("width") != props.end())
383       << "Display configuration missing 'width' in " << flag;
384   CHECK(props.find("height") != props.end())
385       << "Display configuration missing 'height' in " << flag;
386 
387   int display_width;
388   CHECK(android::base::ParseInt(props["width"], &display_width))
389       << "Display configuration invalid 'width' in " << flag;
390 
391   int display_height;
392   CHECK(android::base::ParseInt(props["height"], &display_height))
393       << "Display configuration invalid 'height' in " << flag;
394 
395   int display_dpi = 320;
396   auto display_dpi_it = props.find("dpi");
397   if (display_dpi_it != props.end()) {
398     CHECK(android::base::ParseInt(display_dpi_it->second, &display_dpi))
399         << "Display configuration invalid 'dpi' in " << flag;
400   }
401 
402   int display_refresh_rate_hz = 60;
403   auto display_refresh_rate_hz_it = props.find("refresh_rate_hz");
404   if (display_refresh_rate_hz_it != props.end()) {
405     CHECK(android::base::ParseInt(display_refresh_rate_hz_it->second,
406                                   &display_refresh_rate_hz))
407         << "Display configuration invalid 'refresh_rate_hz' in " << flag;
408   }
409 
410   return CuttlefishConfig::DisplayConfig{
411       .width = display_width,
412       .height = display_height,
413       .dpi = display_dpi,
414       .refresh_rate_hz = display_refresh_rate_hz,
415   };
416 }
417 
418 #ifdef __ANDROID__
ReadKernelConfig()419 Result<KernelConfig> ReadKernelConfig() {
420   // QEMU isn't on Android, so always follow host arch
421   KernelConfig ret{};
422   ret.target_arch = HostArch();
423   ret.bootconfig_supported = true;
424   return ret;
425 }
426 #else
ReadKernelConfig()427 Result<KernelConfig> ReadKernelConfig() {
428   // extract-ikconfig can be called directly on the boot image since it looks
429   // for the ikconfig header in the image before extracting the config list.
430   // This code is liable to break if the boot image ever includes the
431   // ikconfig header outside the kernel.
432   const std::string kernel_image_path =
433       FLAGS_kernel_path.size() ? FLAGS_kernel_path : FLAGS_boot_image;
434 
435   Command ikconfig_cmd(HostBinaryPath("extract-ikconfig"));
436   ikconfig_cmd.AddParameter(kernel_image_path);
437 
438   std::string current_path = StringFromEnv("PATH", "");
439   std::string bin_folder = DefaultHostArtifactsPath("bin");
440   ikconfig_cmd.SetEnvironment({"PATH=" + current_path + ":" + bin_folder});
441 
442   std::string ikconfig_path =
443       StringFromEnv("TEMP", "/tmp") + "/ikconfig.XXXXXX";
444   auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path);
445   CF_EXPECT(ikconfig_fd->IsOpen(),
446             "Unable to create ikconfig file: " << ikconfig_fd->StrError());
447   ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, ikconfig_fd);
448 
449   auto ikconfig_proc = ikconfig_cmd.Start();
450   CF_EXPECT(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0,
451             "Failed to extract ikconfig from " << kernel_image_path);
452 
453   std::string config = ReadFile(ikconfig_path);
454 
455   KernelConfig kernel_config;
456   if (config.find("\nCONFIG_ARM=y") != std::string::npos) {
457     kernel_config.target_arch = Arch::Arm;
458   } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) {
459     kernel_config.target_arch = Arch::Arm64;
460   } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) {
461     kernel_config.target_arch = Arch::X86_64;
462   } else if (config.find("\nCONFIG_X86=y") != std::string::npos) {
463     kernel_config.target_arch = Arch::X86;
464   } else {
465     return CF_ERR("Unknown target architecture");
466   }
467   kernel_config.bootconfig_supported =
468       config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos;
469 
470   unlink(ikconfig_path.c_str());
471   return kernel_config;
472 }
473 #endif  // #ifdef __ANDROID__
474 
475 } // namespace
476 
InitializeCuttlefishConfiguration(const std::string & root_dir,int modem_simulator_count,KernelConfig kernel_config,fruit::Injector<> & injector)477 CuttlefishConfig InitializeCuttlefishConfiguration(
478     const std::string& root_dir, int modem_simulator_count,
479     KernelConfig kernel_config, fruit::Injector<>& injector) {
480   CuttlefishConfig tmp_config_obj;
481 
482   for (const auto& fragment : injector.getMultibindings<ConfigFragment>()) {
483     CHECK(tmp_config_obj.SaveFragment(*fragment))
484         << "Failed to save fragment " << fragment->Name();
485   }
486 
487   tmp_config_obj.set_root_dir(root_dir);
488 
489   tmp_config_obj.set_target_arch(kernel_config.target_arch);
490   tmp_config_obj.set_bootconfig_supported(kernel_config.bootconfig_supported);
491   auto vmm = GetVmManager(FLAGS_vm_manager, kernel_config.target_arch);
492   if (!vmm) {
493     LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
494   }
495   tmp_config_obj.set_vm_manager(FLAGS_vm_manager);
496 
497   std::vector<CuttlefishConfig::DisplayConfig> display_configs;
498 
499   auto display0 = ParseDisplayConfig(FLAGS_display0);
500   if (display0) {
501     display_configs.push_back(*display0);
502   }
503   auto display1 = ParseDisplayConfig(FLAGS_display1);
504   if (display1) {
505     display_configs.push_back(*display1);
506   }
507   auto display2 = ParseDisplayConfig(FLAGS_display2);
508   if (display2) {
509     display_configs.push_back(*display2);
510   }
511   auto display3 = ParseDisplayConfig(FLAGS_display3);
512   if (display3) {
513     display_configs.push_back(*display3);
514   }
515 
516   if (FLAGS_x_res > 0 && FLAGS_y_res > 0) {
517     if (display_configs.empty()) {
518       display_configs.push_back({
519           .width = FLAGS_x_res,
520           .height = FLAGS_y_res,
521           .dpi = FLAGS_dpi,
522           .refresh_rate_hz = FLAGS_refresh_rate_hz,
523       });
524     } else {
525       LOG(WARNING) << "Ignoring --x_res and --y_res when --displayN specified.";
526     }
527   }
528 
529   tmp_config_obj.set_display_configs(display_configs);
530 
531   const GraphicsAvailability graphics_availability =
532     GetGraphicsAvailabilityWithSubprocessCheck();
533 
534   LOG(DEBUG) << graphics_availability;
535 
536   tmp_config_obj.set_gpu_mode(FLAGS_gpu_mode);
537   if (tmp_config_obj.gpu_mode() != kGpuModeAuto &&
538       tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
539       tmp_config_obj.gpu_mode() != kGpuModeGfxStream &&
540       tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
541     LOG(FATAL) << "Invalid gpu_mode: " << FLAGS_gpu_mode;
542   }
543   if (tmp_config_obj.gpu_mode() == kGpuModeAuto) {
544     if (ShouldEnableAcceleratedRendering(graphics_availability)) {
545       LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
546                    "rendering support.";
547       if (FLAGS_vm_manager == QemuManager::name()) {
548         LOG(INFO) << "Enabling --gpu_mode=drm_virgl.";
549         tmp_config_obj.set_gpu_mode(kGpuModeDrmVirgl);
550       } else {
551         LOG(INFO) << "Enabling --gpu_mode=gfxstream.";
552         tmp_config_obj.set_gpu_mode(kGpuModeGfxStream);
553       }
554     } else {
555       LOG(INFO) << "GPU auto mode: did not detect prerequisites for "
556                    "accelerated rendering support, enabling "
557                    "--gpu_mode=guest_swiftshader.";
558       tmp_config_obj.set_gpu_mode(kGpuModeGuestSwiftshader);
559     }
560   } else if (tmp_config_obj.gpu_mode() == kGpuModeGfxStream ||
561              tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) {
562     if (!ShouldEnableAcceleratedRendering(graphics_availability)) {
563       LOG(ERROR) << "--gpu_mode="
564                  << tmp_config_obj.gpu_mode()
565                  << " was requested but the prerequisites for accelerated "
566                     "rendering were not detected so the device may not "
567                     "function correctly. Please consider switching to "
568                     "--gpu_mode=auto or --gpu_mode=guest_swiftshader.";
569     }
570   }
571 
572   tmp_config_obj.set_restart_subprocesses(FLAGS_restart_subprocesses);
573   tmp_config_obj.set_gpu_capture_binary(FLAGS_gpu_capture_binary);
574   if (!tmp_config_obj.gpu_capture_binary().empty()) {
575     CHECK(tmp_config_obj.gpu_mode() == kGpuModeGfxStream)
576         << "GPU capture only supported with --gpu_mode=gfxstream";
577 
578     // GPU capture runs in a detached mode where the "launcher" process
579     // intentionally exits immediately.
580     CHECK(!tmp_config_obj.restart_subprocesses())
581         << "GPU capture only supported with --norestart_subprocesses";
582   }
583 
584   tmp_config_obj.set_hwcomposer(FLAGS_hwcomposer);
585   if (!tmp_config_obj.hwcomposer().empty()) {
586     if (tmp_config_obj.hwcomposer() == kHwComposerRanchu) {
587       CHECK(tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl)
588         << "ranchu hwcomposer not supported with --gpu_mode=drm_virgl";
589     }
590   }
591 
592   if (tmp_config_obj.hwcomposer() == kHwComposerAuto) {
593       if (tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) {
594         tmp_config_obj.set_hwcomposer(kHwComposerDrm);
595       } else {
596         tmp_config_obj.set_hwcomposer(kHwComposerRanchu);
597       }
598   }
599 
600   tmp_config_obj.set_enable_gpu_udmabuf(FLAGS_enable_gpu_udmabuf);
601   tmp_config_obj.set_enable_gpu_angle(FLAGS_enable_gpu_angle);
602 
603   // Sepolicy rules need to be updated to support gpu mode. Temporarily disable
604   // auto-enabling sandbox when gpu is enabled (b/152323505).
605   if (tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
606     SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
607   }
608 
609   if (vmm->ConfigureGraphics(tmp_config_obj).empty()) {
610     LOG(FATAL) << "Invalid (gpu_mode=," << FLAGS_gpu_mode <<
611                " hwcomposer= " << FLAGS_hwcomposer <<
612                ") does not work with vm_manager=" << FLAGS_vm_manager;
613   }
614 
615   CHECK(!FLAGS_smt || FLAGS_cpus % 2 == 0)
616       << "CPUs must be a multiple of 2 in SMT mode";
617   tmp_config_obj.set_cpus(FLAGS_cpus);
618   tmp_config_obj.set_smt(FLAGS_smt);
619 
620   tmp_config_obj.set_memory_mb(FLAGS_memory_mb);
621 
622   tmp_config_obj.set_setupwizard_mode(FLAGS_setupwizard_mode);
623 
624   auto secure_hals = android::base::Split(FLAGS_secure_hals, ",");
625   tmp_config_obj.set_secure_hals(
626       std::set<std::string>(secure_hals.begin(), secure_hals.end()));
627 
628   tmp_config_obj.set_gdb_port(FLAGS_gdb_port);
629 
630   tmp_config_obj.set_guest_enforce_security(FLAGS_guest_enforce_security);
631   tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
632   tmp_config_obj.set_extra_bootconfig_args(FLAGS_extra_bootconfig_args);
633 
634   if (FLAGS_console) {
635     SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
636   }
637 
638   tmp_config_obj.set_console(FLAGS_console);
639   tmp_config_obj.set_kgdb(FLAGS_console && FLAGS_kgdb);
640 
641   tmp_config_obj.set_host_tools_version(HostToolsCrc());
642 
643   tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
644 
645   tmp_config_obj.set_qemu_binary_dir(FLAGS_qemu_binary_dir);
646   tmp_config_obj.set_crosvm_binary(FLAGS_crosvm_binary);
647   tmp_config_obj.set_gem5_binary_dir(FLAGS_gem5_binary_dir);
648 
649   tmp_config_obj.set_seccomp_policy_dir(FLAGS_seccomp_policy_dir);
650 
651   tmp_config_obj.set_enable_webrtc(FLAGS_start_webrtc);
652   tmp_config_obj.set_webrtc_assets_dir(FLAGS_webrtc_assets_dir);
653   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
654   tmp_config_obj.set_sig_server_secure(FLAGS_webrtc_sig_server_secure);
655   // Note: This will be overridden if the sig server is started by us
656   tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
657   tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
658   tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
659   tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
660   tmp_config_obj.set_sig_server_headers_path(FLAGS_sig_server_headers_file);
661 
662   auto tcp_range  = ParsePortRange(FLAGS_tcp_port_range);
663   tmp_config_obj.set_webrtc_tcp_port_range(tcp_range);
664   auto udp_range  = ParsePortRange(FLAGS_udp_port_range);
665   tmp_config_obj.set_webrtc_udp_port_range(udp_range);
666 
667   tmp_config_obj.set_enable_modem_simulator(FLAGS_enable_modem_simulator &&
668                                             !FLAGS_enable_minimal_mode);
669   tmp_config_obj.set_modem_simulator_instance_number(modem_simulator_count);
670   tmp_config_obj.set_modem_simulator_sim_type(FLAGS_modem_simulator_sim_type);
671 
672   tmp_config_obj.set_webrtc_enable_adb_websocket(
673           FLAGS_webrtc_enable_adb_websocket);
674 
675   tmp_config_obj.set_run_as_daemon(FLAGS_daemon);
676 
677   tmp_config_obj.set_data_policy(FLAGS_data_policy);
678   tmp_config_obj.set_blank_data_image_mb(FLAGS_blank_data_image_mb);
679 
680   tmp_config_obj.set_enable_gnss_grpc_proxy(FLAGS_start_gnss_proxy);
681 
682   tmp_config_obj.set_enable_vehicle_hal_grpc_server(
683       FLAGS_enable_vehicle_hal_grpc_server);
684 
685   tmp_config_obj.set_bootloader(FLAGS_bootloader);
686 
687   tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
688 
689   if (!FLAGS_boot_slot.empty()) {
690       tmp_config_obj.set_boot_slot(FLAGS_boot_slot);
691   }
692 
693   tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath());
694 
695   tmp_config_obj.set_ril_dns(FLAGS_ril_dns);
696 
697   tmp_config_obj.set_enable_minimal_mode(FLAGS_enable_minimal_mode);
698 
699   tmp_config_obj.set_vhost_net(FLAGS_vhost_net);
700 
701   tmp_config_obj.set_vhost_user_mac80211_hwsim(FLAGS_vhost_user_mac80211_hwsim);
702 
703   if ((FLAGS_ap_rootfs_image.empty()) != (FLAGS_ap_kernel_image.empty())) {
704     LOG(FATAL) << "Either both ap_rootfs_image and ap_kernel_image should be "
705                   "set or neither should be set.";
706   }
707 
708   tmp_config_obj.set_ap_rootfs_image(FLAGS_ap_rootfs_image);
709   tmp_config_obj.set_ap_kernel_image(FLAGS_ap_kernel_image);
710 
711   tmp_config_obj.set_wmediumd_config(FLAGS_wmediumd_config);
712 
713   tmp_config_obj.set_rootcanal_hci_port(7300);
714   tmp_config_obj.set_rootcanal_link_port(7400);
715   tmp_config_obj.set_rootcanal_test_port(7500);
716   tmp_config_obj.set_rootcanal_config_file(
717       FLAGS_bluetooth_controller_properties_file);
718   tmp_config_obj.set_rootcanal_default_commands_file(
719       FLAGS_bluetooth_default_commands_file);
720 
721   tmp_config_obj.set_record_screen(FLAGS_record_screen);
722 
723   tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth);
724 
725   tmp_config_obj.set_protected_vm(FLAGS_protected_vm);
726 
727   tmp_config_obj.set_userdata_format(FLAGS_userdata_format);
728 
729   std::vector<int> num_instances;
730   for (int i = 0; i < FLAGS_num_instances; i++) {
731     num_instances.push_back(GetInstance() + i);
732   }
733   std::vector<std::string> gnss_file_paths = android::base::Split(FLAGS_gnss_file_path, ",");
734 
735   bool is_first_instance = true;
736   for (const auto& num : num_instances) {
737     IfaceConfig iface_config;
738     if (FLAGS_use_allocd) {
739       auto iface_opt = AllocateNetworkInterfaces();
740       if (!iface_opt.has_value()) {
741         LOG(FATAL) << "Failed to acquire network interfaces";
742       }
743       iface_config = iface_opt.value();
744     } else {
745       iface_config = DefaultNetworkInterfaces(num);
746     }
747 
748     auto instance = tmp_config_obj.ForInstance(num);
749     auto const_instance =
750         const_cast<const CuttlefishConfig&>(tmp_config_obj).ForInstance(num);
751     instance.set_use_allocd(FLAGS_use_allocd);
752     if (FLAGS_use_random_serial) {
753       instance.set_serial_number(
754           RandomSerialNumber("CFCVD" + std::to_string(num)));
755     } else {
756       instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
757     }
758     // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc
759     const auto vsock_guest_cid = FLAGS_vsock_guest_cid + num - GetInstance();
760     instance.set_vsock_guest_cid(vsock_guest_cid);
761     auto calc_vsock_port = [vsock_guest_cid](const int base_port) {
762       // a base (vsock) port is like 9600 for modem_simulator, etc
763       return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid);
764     };
765     instance.set_session_id(iface_config.mobile_tap.session_id);
766 
767     instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
768     instance.set_mobile_tap_name(iface_config.mobile_tap.name);
769     instance.set_wifi_tap_name(iface_config.wireless_tap.name);
770     instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
771 
772     instance.set_uuid(FLAGS_uuid);
773 
774     instance.set_modem_simulator_host_id(1000 + num);  // Must be 4 digits
775     // the deprecated vnc was 6444 + num - 1, and qemu_vnc was vnc - 5900
776     instance.set_qemu_vnc_server_port(544 + num - 1);
777     instance.set_adb_host_port(6520 + num - 1);
778     instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
779     instance.set_confui_host_vsock_port(7700 + num - 1);
780     instance.set_tombstone_receiver_port(calc_vsock_port(6600));
781     instance.set_vehicle_hal_server_port(9300 + num - 1);
782     instance.set_audiocontrol_server_port(9410);  /* OK to use the same port number across instances */
783     instance.set_config_server_port(calc_vsock_port(6800));
784 
785     if (tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
786         tmp_config_obj.gpu_mode() != kGpuModeGfxStream) {
787       if (FLAGS_vm_manager == QemuManager::name()) {
788         instance.set_keyboard_server_port(calc_vsock_port(7000));
789         instance.set_touch_server_port(calc_vsock_port(7100));
790       }
791     }
792 
793     instance.set_gnss_grpc_proxy_server_port(7200 + num -1);
794 
795     if (num <= gnss_file_paths.size()) {
796       instance.set_gnss_file_path(gnss_file_paths[num-1]);
797     }
798 
799     instance.set_camera_server_port(FLAGS_camera_server_port);
800 
801     if (FLAGS_protected_vm) {
802       instance.set_virtual_disk_paths(
803           {const_instance.PerInstancePath("os_composite.img")});
804     } else {
805       std::vector<std::string> virtual_disk_paths = {
806           const_instance.PerInstancePath("persistent_composite.img"),
807       };
808       if (FLAGS_vm_manager != Gem5Manager::name()) {
809         virtual_disk_paths.insert(virtual_disk_paths.begin(),
810             const_instance.PerInstancePath("overlay.img"));
811       } else {
812         // Gem5 already uses CoW wrappers around disk images
813         virtual_disk_paths.insert(virtual_disk_paths.begin(),
814             tmp_config_obj.os_composite_disk_path());
815       }
816       if (FLAGS_use_sdcard) {
817         virtual_disk_paths.push_back(const_instance.sdcard_path());
818       }
819       instance.set_virtual_disk_paths(virtual_disk_paths);
820     }
821 
822     // We'd like to set mac prefix to be 5554, 5555, 5556, ... in normal cases.
823     // When --base_instance_num=3, this might be 5556, 5557, 5558, ... (skipping
824     // first two)
825     instance.set_wifi_mac_prefix(5554 + (num - 1));
826 
827     instance.set_start_webrtc_signaling_server(false);
828 
829     if (FLAGS_webrtc_device_id.empty()) {
830       // Use the instance's name as a default
831       instance.set_webrtc_device_id(const_instance.instance_name());
832     } else {
833       std::string device_id = FLAGS_webrtc_device_id;
834       size_t pos;
835       while ((pos = device_id.find("{num}")) != std::string::npos) {
836         device_id.replace(pos, strlen("{num}"), std::to_string(num));
837       }
838       instance.set_webrtc_device_id(device_id);
839     }
840     if (!is_first_instance || !FLAGS_start_webrtc) {
841       // Only the first instance starts the signaling server or proxy
842       instance.set_start_webrtc_signaling_server(false);
843       instance.set_start_webrtc_sig_server_proxy(false);
844     } else {
845       auto port = 8443 + num - 1;
846       // Change the signaling server port for all instances
847       tmp_config_obj.set_sig_server_port(port);
848       // Either the signaling server or the proxy is started, never both
849       instance.set_start_webrtc_signaling_server(FLAGS_start_webrtc_sig_server);
850       // The proxy is only started if the host operator is available
851       instance.set_start_webrtc_sig_server_proxy(
852           cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH) &&
853           !FLAGS_start_webrtc_sig_server);
854     }
855 
856     // Start wmediumd process for the first instance if
857     // vhost_user_mac80211_hwsim is not specified.
858     const bool start_wmediumd =
859         FLAGS_vhost_user_mac80211_hwsim.empty() && is_first_instance;
860     if (start_wmediumd) {
861       // TODO(b/199020470) move this to the directory for shared resources
862       auto vhost_user_socket_path =
863           const_instance.PerInstanceInternalPath("vhost_user_mac80211");
864       auto wmediumd_api_socket_path =
865           const_instance.PerInstanceInternalPath("wmediumd_api_server");
866 
867       tmp_config_obj.set_vhost_user_mac80211_hwsim(vhost_user_socket_path);
868       tmp_config_obj.set_wmediumd_api_server_socket(wmediumd_api_socket_path);
869       instance.set_start_wmediumd(true);
870     } else {
871       instance.set_start_wmediumd(false);
872     }
873 
874     instance.set_start_rootcanal(is_first_instance);
875 
876     instance.set_start_ap(!FLAGS_ap_rootfs_image.empty() &&
877                           !FLAGS_ap_kernel_image.empty() && is_first_instance);
878 
879     is_first_instance = false;
880 
881     // instance.modem_simulator_ports := "" or "[port,]*port"
882     if (modem_simulator_count > 0) {
883       std::stringstream modem_ports;
884       for (auto index {0}; index < modem_simulator_count - 1; index++) {
885         auto port = 9600 + (modem_simulator_count * (num - 1)) + index;
886         modem_ports << calc_vsock_port(port) << ",";
887       }
888       auto port = 9600 + (modem_simulator_count * (num - 1)) +
889                   modem_simulator_count - 1;
890       modem_ports << calc_vsock_port(port);
891       instance.set_modem_simulator_ports(modem_ports.str());
892     } else {
893       instance.set_modem_simulator_ports("");
894     }
895   } // end of num_instances loop
896 
897   std::vector<std::string> names;
898   for (const auto& instance : tmp_config_obj.Instances()) {
899     names.emplace_back(instance.instance_name());
900   }
901   tmp_config_obj.set_instance_names(names);
902 
903   tmp_config_obj.set_enable_sandbox(FLAGS_enable_sandbox);
904 
905   // Audio is not available for Arm64
906   SetCommandLineOptionWithMode(
907       "enable_audio",
908       (cuttlefish::HostArch() == cuttlefish::Arch::Arm64) ? "false" : "true",
909       SET_FLAGS_DEFAULT);
910   tmp_config_obj.set_enable_audio(FLAGS_enable_audio);
911 
912   return tmp_config_obj;
913 }
914 
SetDefaultFlagsForQemu(Arch target_arch)915 void SetDefaultFlagsForQemu(Arch target_arch) {
916   // for now, we don't set non-default options for QEMU
917   if (FLAGS_gpu_mode == kGpuModeGuestSwiftshader && !FLAGS_start_webrtc) {
918     // This makes WebRTC the default streamer unless the user requests
919     // another via a --star_<streamer> flag, while at the same time it's
920     // possible to run without any streamer by setting --start_webrtc=false.
921     SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
922   }
923   std::string default_bootloader =
924       DefaultHostArtifactsPath("etc/bootloader_");
925   if(target_arch == Arch::Arm) {
926       // Bootloader is unstable >512MB RAM on 32-bit ARM
927       SetCommandLineOptionWithMode("memory_mb", "512", SET_FLAGS_VALUE);
928       default_bootloader += "arm";
929   } else if (target_arch == Arch::Arm64) {
930       default_bootloader += "aarch64";
931   } else {
932       default_bootloader += "x86_64";
933   }
934   default_bootloader += "/bootloader.qemu";
935   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
936                                SET_FLAGS_DEFAULT);
937 }
938 
SetDefaultFlagsForCrosvm()939 void SetDefaultFlagsForCrosvm() {
940   if (!FLAGS_start_webrtc) {
941     // This makes WebRTC the default streamer unless the user requests
942     // another via a --star_<streamer> flag, while at the same time it's
943     // possible to run without any streamer by setting --start_webrtc=false.
944     SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
945   }
946 
947   std::set<Arch> supported_archs{Arch::X86_64};
948   bool default_enable_sandbox =
949       supported_archs.find(HostArch()) != supported_archs.end() &&
950       EnsureDirectoryExists(kCrosvmVarEmptyDir).ok() &&
951       IsDirectoryEmpty(kCrosvmVarEmptyDir) && !IsRunningInContainer();
952   SetCommandLineOptionWithMode("enable_sandbox",
953                                (default_enable_sandbox ? "true" : "false"),
954                                SET_FLAGS_DEFAULT);
955 
956   std::string default_bootloader = FLAGS_system_image_dir + "/bootloader";
957   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
958                                SET_FLAGS_DEFAULT);
959 }
960 
SetDefaultFlagsForGem5()961 void SetDefaultFlagsForGem5() {
962   // TODO: Add support for gem5 gpu models
963   SetCommandLineOptionWithMode("gpu_mode", kGpuModeGuestSwiftshader,
964                                SET_FLAGS_DEFAULT);
965 
966   SetCommandLineOptionWithMode("cpus", "1", SET_FLAGS_DEFAULT);
967 }
968 
GetKernelConfigAndSetDefaults()969 Result<KernelConfig> GetKernelConfigAndSetDefaults() {
970   CF_EXPECT(ResolveInstanceFiles(), "Failed to resolve instance files");
971 
972   KernelConfig kernel_config = CF_EXPECT(ReadKernelConfig());
973 
974   if (FLAGS_vm_manager == "") {
975     if (IsHostCompatible(kernel_config.target_arch)) {
976       FLAGS_vm_manager = CrosvmManager::name();
977     } else {
978       FLAGS_vm_manager = QemuManager::name();
979     }
980   }
981 
982   if (FLAGS_vm_manager == QemuManager::name()) {
983     SetDefaultFlagsForQemu(kernel_config.target_arch);
984   } else if (FLAGS_vm_manager == CrosvmManager::name()) {
985     SetDefaultFlagsForCrosvm();
986   } else if (FLAGS_vm_manager == Gem5Manager::name()) {
987     // TODO: Get the other architectures working
988     if (kernel_config.target_arch != Arch::Arm64) {
989       return CF_ERR("Gem5 only supports ARM64");
990     }
991     SetDefaultFlagsForGem5();
992   } else {
993     return CF_ERR("Unknown Virtual Machine Manager: " << FLAGS_vm_manager);
994   }
995   if (FLAGS_vm_manager != Gem5Manager::name()) {
996     auto host_operator_present =
997         cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH);
998     // The default for starting signaling server depends on whether or not webrtc
999     // is to be started and the presence of the host orchestrator.
1000     SetCommandLineOptionWithMode(
1001         "start_webrtc_sig_server",
1002         FLAGS_start_webrtc && !host_operator_present ? "true" : "false",
1003         SET_FLAGS_DEFAULT);
1004     SetCommandLineOptionWithMode(
1005         "webrtc_sig_server_addr",
1006         host_operator_present ? HOST_OPERATOR_SOCKET_PATH : "0.0.0.0",
1007         SET_FLAGS_DEFAULT);
1008   }
1009   // Set the env variable to empty (in case the caller passed a value for it).
1010   unsetenv(kCuttlefishConfigEnvVarName);
1011 
1012   return kernel_config;
1013 }
1014 
GetConfigFilePath(const CuttlefishConfig & config)1015 std::string GetConfigFilePath(const CuttlefishConfig& config) {
1016   return config.AssemblyPath("cuttlefish_config.json");
1017 }
1018 
GetCuttlefishEnvPath()1019 std::string GetCuttlefishEnvPath() {
1020   return StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
1021 }
1022 
1023 } // namespace cuttlefish
1024