• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #include "host/commands/assemble_cvd/flags.h"
17 
18 #include <sys/types.h>
19 #include <unistd.h>
20 
21 #include <algorithm>
22 #include <fstream>
23 #include <iostream>
24 #include <optional>
25 #include <regex>
26 #include <set>
27 #include <sstream>
28 #include <unordered_map>
29 
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/parseint.h>
33 #include <android-base/strings.h>
34 #include <fmt/format.h>
35 #include <fruit/fruit.h>
36 #include <gflags/gflags.h>
37 #include <google/protobuf/text_format.h>
38 #include <json/json.h>
39 #include <json/writer.h>
40 
41 #include "common/libs/utils/architecture.h"
42 #include "common/libs/utils/base64.h"
43 #include "common/libs/utils/container.h"
44 #include "common/libs/utils/contains.h"
45 #include "common/libs/utils/environment.h"
46 #include "common/libs/utils/files.h"
47 #include "common/libs/utils/flag_parser.h"
48 #include "common/libs/utils/in_sandbox.h"
49 #include "common/libs/utils/json.h"
50 #include "common/libs/utils/known_paths.h"
51 #include "common/libs/utils/network.h"
52 #include "host/commands/assemble_cvd/alloc.h"
53 #include "host/commands/assemble_cvd/boot_config.h"
54 #include "host/commands/assemble_cvd/boot_image_utils.h"
55 #include "host/commands/assemble_cvd/disk_flags.h"
56 #include "host/commands/assemble_cvd/display.h"
57 #include "host/commands/assemble_cvd/flags_defaults.h"
58 #include "host/commands/assemble_cvd/graphics_flags.h"
59 #include "host/commands/assemble_cvd/misc_info.h"
60 #include "host/commands/assemble_cvd/network_flags.h"
61 #include "host/commands/assemble_cvd/touchpad.h"
62 #include "host/libs/config/config_flag.h"
63 #include "host/libs/config/cuttlefish_config.h"
64 #include "host/libs/config/display.h"
65 #include "host/libs/config/esp.h"
66 #include "host/libs/config/host_tools_version.h"
67 #include "host/libs/config/instance_nums.h"
68 #include "host/libs/config/secure_hals.h"
69 #include "host/libs/config/touchpad.h"
70 #include "host/libs/vhal_proxy_server/vhal_proxy_server_eth_addr.h"
71 #include "host/libs/vm_manager/crosvm_manager.h"
72 #include "host/libs/vm_manager/gem5_manager.h"
73 #include "host/libs/vm_manager/qemu_manager.h"
74 #include "host/libs/vm_manager/vm_manager.h"
75 #include "launch_cvd.pb.h"
76 
77 using cuttlefish::DefaultHostArtifactsPath;
78 using cuttlefish::HostBinaryPath;
79 using cuttlefish::TempDir;
80 using cuttlefish::vm_manager::CrosvmManager;
81 using google::FlagSettingMode::SET_FLAGS_DEFAULT;
82 using google::FlagSettingMode::SET_FLAGS_VALUE;
83 
84 #define DEFINE_vec DEFINE_string
85 #define DEFINE_proto DEFINE_string
86 #define GET_FLAG_STR_VALUE(name) GetFlagStrValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
87 #define GET_FLAG_INT_VALUE(name) GetFlagIntValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
88 #define GET_FLAG_BOOL_VALUE(name) GetFlagBoolValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
89 
90 DEFINE_proto(displays_textproto, CF_DEFAULTS_DISPLAYS_TEXTPROTO,
91               "Text Proto input for multi-vd multi-displays");
92 DEFINE_proto(displays_binproto, CF_DEFAULTS_DISPLAYS_TEXTPROTO,
93               "Binary Proto input for multi-vd multi-displays");
94 
95 DEFINE_vec(cpus, std::to_string(CF_DEFAULTS_CPUS),
96               "Virtual CPU count.");
97 DEFINE_vec(data_policy, CF_DEFAULTS_DATA_POLICY,
98               "How to handle userdata partition."
99               " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
100               "'always_create'.");
101 DEFINE_vec(blank_data_image_mb,
102               std::to_string(CF_DEFAULTS_BLANK_DATA_IMAGE_MB),
103              "The size of the blank data image to generate, MB.");
104 DEFINE_vec(gdb_port, std::to_string(CF_DEFAULTS_GDB_PORT),
105              "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The"
106              "kernel must have been built with CONFIG_RANDOMIZE_BASE "
107              "disabled.");
108 
109 // TODO(b/192495477): combine these into a single repeatable '--display' flag
110 // when assemble_cvd switches to using the new flag parsing library.
111 DEFINE_string(display0, CF_DEFAULTS_DISPLAY0, cuttlefish::kDisplayHelp);
112 DEFINE_string(display1, CF_DEFAULTS_DISPLAY1, cuttlefish::kDisplayHelp);
113 DEFINE_string(display2, CF_DEFAULTS_DISPLAY2, cuttlefish::kDisplayHelp);
114 DEFINE_string(display3, CF_DEFAULTS_DISPLAY3, cuttlefish::kDisplayHelp);
115 
116 // TODO(b/171305898): mark these as deprecated after multi-display is fully
117 // enabled.
118 DEFINE_string(x_res, "0", "Width of the screen in pixels");
119 DEFINE_string(y_res, "0", "Height of the screen in pixels");
120 DEFINE_string(dpi, "0", "Pixels per inch for the screen");
121 DEFINE_string(refresh_rate_hz, "60", "Screen refresh rate in Hertz");
122 DEFINE_string(overlays, "",
123               "List of displays to overlay. Format is: 'vm_index:display_index "
124               "vm_index2:display_index2 [...]'");
125 DEFINE_bool(use_16k, false, "Launch using 16k kernel");
126 DEFINE_vec(kernel_path, CF_DEFAULTS_KERNEL_PATH,
127               "Path to the kernel. Overrides the one from the boot image");
128 DEFINE_vec(initramfs_path, CF_DEFAULTS_INITRAMFS_PATH,
129               "Path to the initramfs");
130 DEFINE_string(extra_kernel_cmdline, CF_DEFAULTS_EXTRA_KERNEL_CMDLINE,
131               "Additional flags to put on the kernel command line");
132 DEFINE_string(extra_bootconfig_args, CF_DEFAULTS_EXTRA_BOOTCONFIG_ARGS,
133               "Space-separated list of extra bootconfig args. "
134               "Note: overwriting an existing bootconfig argument "
135               "requires ':=' instead of '='.");
136 DEFINE_vec(guest_enforce_security,
137            fmt::format("{}", CF_DEFAULTS_GUEST_ENFORCE_SECURITY),
138            "Whether to run in enforcing mode (non permissive).");
139 DEFINE_vec(memory_mb, std::to_string(CF_DEFAULTS_MEMORY_MB),
140              "Total amount of memory available for guest, MB.");
141 DEFINE_vec(serial_number, CF_DEFAULTS_SERIAL_NUMBER,
142               "Serial number to use for the device");
143 DEFINE_vec(use_random_serial, fmt::format("{}", CF_DEFAULTS_USE_RANDOM_SERIAL),
144            "Whether to use random serial for the device.");
145 DEFINE_vec(vm_manager, CF_DEFAULTS_VM_MANAGER,
146               "What virtual machine manager to use, one of {qemu_cli, crosvm}");
147 DEFINE_vec(gpu_mode, CF_DEFAULTS_GPU_MODE,
148            "What gpu configuration to use, one of {auto, custom, drm_virgl, "
149            "gfxstream, gfxstream_guest_angle, "
150            "gfxstream_guest_angle_host_swiftshader, "
151            "gfxstream_guest_angle_host_lavapipe, guest_swiftshader}");
152 DEFINE_vec(gpu_vhost_user_mode,
153            fmt::format("{}", CF_DEFAULTS_GPU_VHOST_USER_MODE),
154            "Whether or not to run the Virtio GPU worker in a separate"
155            "process using vhost-user-gpu. One of {auto, on, off}.");
156 DEFINE_vec(hwcomposer, CF_DEFAULTS_HWCOMPOSER,
157               "What hardware composer to use, one of {auto, drm, ranchu} ");
158 DEFINE_vec(gpu_capture_binary, CF_DEFAULTS_GPU_CAPTURE_BINARY,
159               "Path to the GPU capture binary to use when capturing GPU traces"
160               "(ngfx, renderdoc, etc)");
161 DEFINE_vec(enable_gpu_udmabuf,
162            fmt::format("{}", CF_DEFAULTS_ENABLE_GPU_UDMABUF),
163            "Use the udmabuf driver for zero-copy virtio-gpu");
164 DEFINE_vec(
165     gpu_renderer_features, CF_DEFAULTS_GPU_RENDERER_FEATURES,
166     "Renderer specific features to enable. For Gfxstream, this should "
167     "be a semicolon separated list of \"<feature name>:[enabled|disabled]\""
168     "pairs.");
169 
170 DEFINE_vec(gpu_context_types, CF_DEFAULTS_GPU_CONTEXT_TYPES,
171            "A colon separated list of virtio-gpu context types.  Only valid "
172            "with --gpu_mode=custom."
173            " For example \"--gpu_context_types=cross_domain:gfxstream\"");
174 
175 DEFINE_vec(
176     guest_hwui_renderer, CF_DEFAULTS_GUEST_HWUI_RENDERER,
177     "The default renderer that HWUI should use, one of {skiagl, skiavk}.");
178 
179 DEFINE_vec(guest_renderer_preload, CF_DEFAULTS_GUEST_RENDERER_PRELOAD,
180            "Whether or not Zygote renderer preload is disabled, one of {auto, "
181            "enabled, disabled}. Auto will choose whether or not to disable "
182            "based on the gpu mode and guest hwui renderer.");
183 
184 DEFINE_vec(
185     guest_vulkan_driver, CF_DEFAULTS_GUEST_VULKAN_DRIVER,
186     "Vulkan driver to use with Cuttlefish.  Android VMs require specifying "
187     "this at boot time.  Only valid with --gpu_mode=custom. "
188     "For example \"--guest_vulkan_driver=ranchu\"");
189 
190 DEFINE_vec(
191     frames_socket_path, CF_DEFAULTS_FRAME_SOCKET_PATH,
192     "Frame socket path to use when launching a VM "
193     "For example, \"--frames_socket_path=${XDG_RUNTIME_DIR}/wayland-0\"");
194 
195 DEFINE_vec(use_allocd, CF_DEFAULTS_USE_ALLOCD?"true":"false",
196             "Acquire static resources from the resource allocator daemon.");
197 DEFINE_vec(
198     enable_minimal_mode, CF_DEFAULTS_ENABLE_MINIMAL_MODE ? "true" : "false",
199     "Only enable the minimum features to boot a cuttlefish device and "
200     "support minimal UI interactions.\nNote: Currently only supports "
201     "handheld/phone targets");
202 DEFINE_vec(
203     pause_in_bootloader, CF_DEFAULTS_PAUSE_IN_BOOTLOADER?"true":"false",
204     "Stop the bootflow in u-boot. You can continue the boot by connecting "
205     "to the device console and typing in \"boot\".");
206 DEFINE_bool(enable_host_bluetooth, CF_DEFAULTS_ENABLE_HOST_BLUETOOTH,
207             "Enable the root-canal which is Bluetooth emulator in the host.");
208 DEFINE_int32(
209     rootcanal_instance_num, CF_DEFAULTS_ROOTCANAL_INSTANCE_NUM,
210     "If it is greater than 0, use an existing rootcanal instance which is "
211     "launched from cuttlefish instance "
212     "with rootcanal_instance_num. Else, launch a new rootcanal instance");
213 DEFINE_string(rootcanal_args, CF_DEFAULTS_ROOTCANAL_ARGS,
214               "Space-separated list of rootcanal args. ");
215 DEFINE_bool(enable_host_nfc, CF_DEFAULTS_ENABLE_HOST_NFC,
216             "Enable the NFC emulator in the host.");
217 DEFINE_int32(
218     casimir_instance_num, CF_DEFAULTS_CASIMIR_INSTANCE_NUM,
219     "If it is greater than 0, use an existing casimir instance which is "
220     "launched from cuttlefish instance "
221     "with casimir_instance_num. Else, launch a new casimir instance");
222 DEFINE_string(casimir_args, CF_DEFAULTS_CASIMIR_ARGS,
223               "Space-separated list of casimir args.");
224 DEFINE_bool(enable_host_uwb, CF_DEFAULTS_ENABLE_HOST_UWB,
225             "Enable the uwb host and the uwb connector.");
226 DEFINE_int32(
227     pica_instance_num, CF_DEFAULTS_ENABLE_PICA_INSTANCE_NUM,
228     "If it is greater than 0, use an existing pica instance which is "
229     "launched from cuttlefish instance "
230     "with pica_instance_num. Else, launch a new pica instance");
231 DEFINE_bool(netsim, CF_DEFAULTS_NETSIM,
232             "[Experimental] Connect all radios to netsim.");
233 
234 DEFINE_bool(netsim_bt, CF_DEFAULTS_NETSIM_BT,
235             "Connect Bluetooth radio to netsim.");
236 DEFINE_bool(netsim_uwb, CF_DEFAULTS_NETSIM_UWB,
237             "[Experimental] Connect Uwb radio to netsim.");
238 DEFINE_string(netsim_args, CF_DEFAULTS_NETSIM_ARGS,
239               "Space-separated list of netsim args.");
240 
241 DEFINE_bool(enable_automotive_proxy, CF_DEFAULTS_ENABLE_AUTOMOTIVE_PROXY,
242             "Enable the automotive proxy service on the host.");
243 
244 DEFINE_bool(enable_vhal_proxy_server, CF_DEFAULTS_ENABLE_VHAL_PROXY_SERVER,
245             "Enable the vhal proxy service on the host.");
246 DEFINE_int32(vhal_proxy_server_instance_num,
247              CF_DEFAULTS_VHAL_PROXY_SERVER_INSTANCE_NUM,
248              "If it is greater than 0, use an existing vhal proxy server "
249              "instance which is "
250              "launched from cuttlefish instance "
251              "with vhal_proxy_server_instance_num. Else, launch a new vhal "
252              "proxy server instance");
253 
254 /**
255  * crosvm sandbox feature requires /var/empty and seccomp directory
256  *
257  * Also see SetDefaultFlagsForCrosvm()
258  */
259 DEFINE_vec(
260     enable_sandbox, fmt::format("{}", CF_DEFAULTS_ENABLE_SANDBOX),
261     "Enable crosvm sandbox assuming /var/empty and seccomp directories exist. "
262     "--noenable-sandbox will disable crosvm sandbox. "
263     "When no option is given, sandbox is disabled if Cuttlefish is running "
264     "inside a container, or if GPU is enabled (b/152323505), "
265     "or if the empty /var/empty directory either does not exist and "
266     "cannot be created. Otherwise, sandbox is enabled on the supported "
267     "architecture when no option is given.");
268 
269 DEFINE_vec(enable_virtiofs, fmt::format("{}", CF_DEFAULTS_ENABLE_VIRTIOFS),
270            "Enable shared folder using virtiofs");
271 
272 DEFINE_string(
273     seccomp_policy_dir, CF_DEFAULTS_SECCOMP_POLICY_DIR,
274     "With sandbox'ed crosvm, overrieds the security comp policy directory");
275 
276 DEFINE_vec(start_webrtc, fmt::format("{}", CF_DEFAULTS_START_WEBRTC),
277            "Whether to start the webrtc process.");
278 
279 DEFINE_vec(webrtc_assets_dir, CF_DEFAULTS_WEBRTC_ASSETS_DIR,
280               "[Experimental] Path to WebRTC webpage assets.");
281 
282 DEFINE_string(webrtc_certs_dir, CF_DEFAULTS_WEBRTC_CERTS_DIR,
283               "[Experimental] Path to WebRTC certificates directory.");
284 
285 static constexpr auto HOST_OPERATOR_SOCKET_PATH = "/run/cuttlefish/operator";
286 
287 DEFINE_bool(
288     // The actual default for this flag is set with SetCommandLineOption() in
289     // GetGuestConfigsAndSetDefaults() at the end of this file.
290     start_webrtc_sig_server, CF_DEFAULTS_START_WEBRTC_SIG_SERVER,
291     "Whether to start the webrtc signaling server. This option only applies to "
292     "the first instance, if multiple instances are launched they'll share the "
293     "same signaling server, which is owned by the first one.");
294 
295 DEFINE_string(webrtc_sig_server_addr, CF_DEFAULTS_WEBRTC_SIG_SERVER_ADDR,
296               "The address of the webrtc signaling server.");
297 
298 DEFINE_int32(
299     webrtc_sig_server_port, CF_DEFAULTS_WEBRTC_SIG_SERVER_PORT,
300     "The port of the signaling server if started outside of this launch. If "
301     "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
302     "this parameter is ignored.");
303 
304 // TODO (jemoreira): We need a much bigger range to reliably support several
305 // simultaneous connections.
306 DEFINE_vec(tcp_port_range, CF_DEFAULTS_TCP_PORT_RANGE,
307               "The minimum and maximum TCP port numbers to allocate for ICE "
308               "candidates as 'min:max'. To use any port just specify '0:0'");
309 
310 DEFINE_vec(udp_port_range, CF_DEFAULTS_UDP_PORT_RANGE,
311               "The minimum and maximum UDP port numbers to allocate for ICE "
312               "candidates as 'min:max'. To use any port just specify '0:0'");
313 
314 DEFINE_string(webrtc_sig_server_path, CF_DEFAULTS_WEBRTC_SIG_SERVER_PATH,
315               "The path section of the URL where the device should be "
316               "registered with the signaling server.");
317 
318 DEFINE_bool(
319     webrtc_sig_server_secure, CF_DEFAULTS_WEBRTC_SIG_SERVER_SECURE,
320     "Whether the WebRTC signaling server uses secure protocols (WSS vs WS).");
321 
322 DEFINE_bool(verify_sig_server_certificate,
323             CF_DEFAULTS_VERIFY_SIG_SERVER_CERTIFICATE,
324             "Whether to verify the signaling server's certificate with a "
325             "trusted signing authority (Disallow self signed certificates). "
326             "This is ignored if an insecure server is configured.");
327 
328 DEFINE_string(group_id, "", "The group name of instance");
329 
330 DEFINE_vec(
331     webrtc_device_id, CF_DEFAULTS_WEBRTC_DEVICE_ID,
332     "The for the device to register with the signaling server. Every "
333     "appearance of the substring '{num}' in the device id will be substituted "
334     "with the instance number to support multiple instances");
335 
336 DEFINE_vec(uuid, CF_DEFAULTS_UUID,
337               "UUID to use for the device. Random if not specified");
338 DEFINE_vec(daemon, CF_DEFAULTS_DAEMON?"true":"false",
339             "Run cuttlefish in background, the launcher exits on boot "
340             "completed/failed");
341 
342 DEFINE_vec(setupwizard_mode, CF_DEFAULTS_SETUPWIZARD_MODE,
343               "One of DISABLED,OPTIONAL,REQUIRED");
344 DEFINE_vec(enable_bootanimation,
345            fmt::format("{}", CF_DEFAULTS_ENABLE_BOOTANIMATION),
346            "Whether to enable the boot animation.");
347 
348 DEFINE_vec(extra_bootconfig_args_base64, CF_DEFAULTS_EXTRA_BOOTCONFIG_ARGS,
349            "This is base64 encoded version of extra_bootconfig_args"
350            "Used for multi device clusters.");
351 
352 DEFINE_string(qemu_binary_dir, CF_DEFAULTS_QEMU_BINARY_DIR,
353               "Path to the directory containing the qemu binary to use");
354 DEFINE_string(crosvm_binary, CF_DEFAULTS_CROSVM_BINARY,
355               "The Crosvm binary to use");
356 DEFINE_vec(gem5_binary_dir, CF_DEFAULTS_GEM5_BINARY_DIR,
357               "Path to the gem5 build tree root");
358 DEFINE_vec(gem5_checkpoint_dir, CF_DEFAULTS_GEM5_CHECKPOINT_DIR,
359               "Path to the gem5 restore checkpoint directory");
360 DEFINE_vec(gem5_debug_file, CF_DEFAULTS_GEM5_DEBUG_FILE,
361               "The file name where gem5 saves debug prints and logs");
362 DEFINE_string(gem5_debug_flags, CF_DEFAULTS_GEM5_DEBUG_FLAGS,
363               "The debug flags gem5 uses to print debugs to file");
364 
365 DEFINE_vec(restart_subprocesses,
366            fmt::format("{}", CF_DEFAULTS_RESTART_SUBPROCESSES),
367            "Restart any crashed host process");
368 DEFINE_vec(bootloader, CF_DEFAULTS_BOOTLOADER, "Bootloader binary path");
369 DEFINE_vec(boot_slot, CF_DEFAULTS_BOOT_SLOT,
370               "Force booting into the given slot. If empty, "
371               "the slot will be chosen based on the misc partition if using a "
372               "bootloader. It will default to 'a' if empty and not using a "
373               "bootloader.");
374 DEFINE_int32(num_instances, CF_DEFAULTS_NUM_INSTANCES,
375              "Number of Android guests to launch");
376 DEFINE_string(instance_nums, CF_DEFAULTS_INSTANCE_NUMS,
377               "A comma-separated list of instance numbers "
378               "to use. Mutually exclusive with base_instance_num.");
379 DEFINE_string(report_anonymous_usage_stats,
380               CF_DEFAULTS_REPORT_ANONYMOUS_USAGE_STATS,
381               "Report anonymous usage "
382               "statistics for metrics collection and analysis.");
383 DEFINE_vec(ril_dns, CF_DEFAULTS_RIL_DNS,
384               "DNS address of mobile network (RIL)");
385 DEFINE_vec(kgdb, fmt::format("{}", CF_DEFAULTS_KGDB),
386            "Configure the virtual device for debugging the kernel "
387            "with kgdb/kdb. The kernel must have been built with "
388            "kgdb support, and serial console must be enabled.");
389 
390 DEFINE_vec(start_gnss_proxy, fmt::format("{}", CF_DEFAULTS_START_GNSS_PROXY),
391            "Whether to start the gnss proxy.");
392 
393 DEFINE_vec(gnss_file_path, CF_DEFAULTS_GNSS_FILE_PATH,
394               "Local gnss raw measurement file path for the gnss proxy");
395 
396 DEFINE_vec(fixed_location_file_path, CF_DEFAULTS_FIXED_LOCATION_FILE_PATH,
397               "Local fixed location file path for the gnss proxy");
398 
399 // by default, this modem-simulator is disabled
400 DEFINE_vec(enable_modem_simulator,
401               CF_DEFAULTS_ENABLE_MODEM_SIMULATOR ? "true" : "false",
402               "Enable the modem simulator to process RILD AT commands");
403 // modem_simulator_sim_type=2 for test CtsCarrierApiTestCases
404 DEFINE_vec(modem_simulator_sim_type,
405               std::to_string(CF_DEFAULTS_MODEM_SIMULATOR_SIM_TYPE),
406               "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
407 
408 DEFINE_vec(console, fmt::format("{}", CF_DEFAULTS_CONSOLE),
409            "Enable the serial console");
410 
411 DEFINE_vec(enable_kernel_log, fmt::format("{}", CF_DEFAULTS_ENABLE_KERNEL_LOG),
412            "Enable kernel console/dmesg logging");
413 
414 DEFINE_vec(vhost_net, fmt::format("{}", CF_DEFAULTS_VHOST_NET),
415            "Enable vhost acceleration of networking");
416 
417 DEFINE_vec(vhost_user_vsock, fmt::format("{}", CF_DEFAULTS_VHOST_USER_VSOCK),
418            "Enable vhost-user-vsock");
419 
420 DEFINE_string(
421     vhost_user_mac80211_hwsim, CF_DEFAULTS_VHOST_USER_MAC80211_HWSIM,
422     "Unix socket path for vhost-user of mac80211_hwsim, typically served by "
423     "wmediumd. You can set this when using an external wmediumd instance.");
424 DEFINE_string(wmediumd_config, CF_DEFAULTS_WMEDIUMD_CONFIG,
425               "Path to the wmediumd config file. When missing, the default "
426               "configuration is used which adds MAC addresses for up to 16 "
427               "cuttlefish instances including AP.");
428 
429 DEFINE_string(ap_rootfs_image, CF_DEFAULTS_AP_ROOTFS_IMAGE,
430               "rootfs image for AP instance");
431 DEFINE_string(ap_kernel_image, CF_DEFAULTS_AP_KERNEL_IMAGE,
432               "kernel image for AP instance");
433 
434 DEFINE_vec(record_screen, fmt::format("{}", CF_DEFAULTS_RECORD_SCREEN),
435            "Enable screen recording. "
436            "Requires --start_webrtc");
437 
438 DEFINE_vec(smt, fmt::format("{}", CF_DEFAULTS_SMT),
439            "Enable simultaneous multithreading (SMT/HT)");
440 
441 DEFINE_vec(
442     vsock_guest_cid, std::to_string(CF_DEFAULTS_VSOCK_GUEST_CID),
443     "vsock_guest_cid is used to determine the guest vsock cid as well as all "
444     "the ports"
445     "of all vsock servers such as tombstone or modem simulator(s)."
446     "The vsock ports and guest vsock cid are a function of vsock_guest_cid and "
447     "instance number."
448     "An instance number of i th instance is determined by --num_instances=N "
449     "and --base_instance_num=B"
450     "The instance number of i th instance is B + i where i in [0, N-1] and B "
451     ">= 1."
452     "See --num_instances, and --base_instance_num for more information"
453     "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. "
454     "Otherwise,"
455     "the guest vsock cid is 2 + instance number, which is 2 + (B + i)."
456     "If --vsock_guest_cid is not given, each vsock server port number for i th "
457     "instance is"
458     "base + instance number - 1. vsock_guest_cid is by default B + i + 2."
459     "Thus, by default, each port is base + vsock_guest_cid - 3."
460     "The same formula holds when --vsock_guest_cid=C is given, for algorithm's "
461     "sake."
462     "Each vsock server port number is base + C - 3.");
463 
464 DEFINE_vec(
465     vsock_guest_group, CF_DEFAULTS_VSOCK_GUEST_GROUP,
466     "vsock_guest_group is used to determine the guest vsock isolation groups."
467     "vsock communications can only happen between VMs which are tagged with "
468     "the same group name, or between VMs which have no group assigned.");
469 
470 DEFINE_string(secure_hals, CF_DEFAULTS_SECURE_HALS,
471               "Which HALs to use enable host security features for. Supports "
472               "keymint and gatekeeper at the moment.");
473 
474 DEFINE_vec(use_sdcard, CF_DEFAULTS_USE_SDCARD?"true":"false",
475             "Create blank SD-Card image and expose to guest");
476 
477 DEFINE_vec(protected_vm, fmt::format("{}", CF_DEFAULTS_PROTECTED_VM),
478            "Boot in Protected VM mode");
479 
480 DEFINE_vec(mte, fmt::format("{}", CF_DEFAULTS_MTE), "Enable MTE");
481 
482 DEFINE_vec(enable_audio, fmt::format("{}", CF_DEFAULTS_ENABLE_AUDIO),
483            "Whether to play or capture audio");
484 
485 DEFINE_vec(enable_usb, fmt::format("{}", CF_DEFAULTS_ENABLE_USB),
486            "Whether to allow USB passthrough on the device");
487 
488 DEFINE_vec(camera_server_port, std::to_string(CF_DEFAULTS_CAMERA_SERVER_PORT),
489               "camera vsock port");
490 
491 DEFINE_vec(userdata_format, CF_DEFAULTS_USERDATA_FORMAT,
492               "The userdata filesystem format");
493 
494 DEFINE_bool(use_overlay, CF_DEFAULTS_USE_OVERLAY,
495             "Capture disk writes an overlay. This is a "
496             "prerequisite for powerwash_cvd or multiple instances.");
497 
498 DEFINE_vec(modem_simulator_count,
499            std::to_string(CF_DEFAULTS_MODEM_SIMULATOR_COUNT),
500            "Modem simulator count corresponding to maximum sim number");
501 
502 DEFINE_bool(track_host_tools_crc, CF_DEFAULTS_TRACK_HOST_TOOLS_CRC,
503             "Track changes to host executables");
504 
505 // The default value should be set to the default of crosvm --balloon
506 DEFINE_vec(crosvm_use_balloon, "true",
507            "Controls the crosvm --no-balloon flag"
508            "The flag is given if crosvm_use_balloon is false");
509 
510 DEFINE_vec(crosvm_use_rng, "true",
511            "Controls the crosvm --no-rng flag"
512            "The flag is given if crosvm_use_rng is false");
513 
514 DEFINE_vec(crosvm_simple_media_device, "false",
515            "Controls the crosvm --simple-media-device flag"
516            "The flag is given if crosvm_simple_media_device is true.");
517 
518 DEFINE_vec(crosvm_v4l2_proxy, CF_DEFAULTS_CROSVM_V4L2_PROXY,
519            "Controls the crosvm --v4l2-proxy flag"
520            "The flag is given if crosvm_v4l2_proxy is set with a valid string literal. "
521            "When this flag is set, crosvm_simple_media_device becomes ineffective.");
522 
523 DEFINE_vec(use_pmem, "true",
524            "Make this flag false to disable pmem with crosvm");
525 
526 DEFINE_bool(enable_wifi, true, "Enables the guest WIFI. Mainly for Minidroid");
527 
528 DEFINE_vec(device_external_network, CF_DEFAULTS_DEVICE_EXTERNAL_NETWORK,
529            "The mechanism to connect to the public internet.");
530 
531 // disable wifi, disable sandbox, use guest_swiftshader
532 DEFINE_bool(snapshot_compatible, false,
533             "Declaring that device is snapshot'able and runs with only "
534             "supported ones.");
535 
536 DEFINE_vec(mcu_config_path, CF_DEFAULTS_MCU_CONFIG_PATH,
537            "configuration file for the MCU emulator");
538 
539 DEFINE_string(straced_host_executables, CF_DEFAULTS_STRACED_HOST_EXECUTABLES,
540               "Comma-separated list of executable names to run under strace "
541               "to collect their system call information.");
542 
543 DEFINE_vec(
544     fail_fast, CF_DEFAULTS_FAIL_FAST ? "true" : "false",
545     "Whether to exit when a heuristic predicts the boot will not complete");
546 
547 DEFINE_vec(vhost_user_block, CF_DEFAULTS_VHOST_USER_BLOCK ? "true" : "false",
548            "(experimental) use crosvm vhost-user block device implementation ");
549 
550 DEFINE_string(early_tmp_dir, TempDir(),
551               "Parent directory to use for temporary files in early startup");
552 
553 DEFINE_vec(enable_tap_devices, "true",
554            "TAP devices are used on linux for connecting to the network "
555            "outside the current machine.");
556 
557 DECLARE_string(assembly_dir);
558 DECLARE_string(boot_image);
559 DECLARE_string(system_image_dir);
560 DECLARE_string(snapshot_path);
561 
562 DEFINE_vec(vcpu_config_path, CF_DEFAULTS_VCPU_CONFIG_PATH,
563            "configuration file for Virtual Cpufreq");
564 
565 DEFINE_string(kvm_path, "",
566               "Device node file used to create VMs. Uses a default if empty.");
567 
568 DEFINE_string(vhost_vsock_path, "",
569               "Device node file for the kernel vhost-vsock implementation. "
570               "Uses a default if empty. Ignored for QEMU.");
571 
572 namespace cuttlefish {
573 using vm_manager::QemuManager;
574 using vm_manager::Gem5Manager;
575 using vm_manager::GetVmManager;
576 
577 namespace {
578 
ParsePortRange(const std::string & flag)579 std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
580   static const std::regex rgx("[0-9]+:[0-9]+");
581   CHECK(std::regex_match(flag, rgx))
582       << "Port range flag has invalid value: " << flag;
583   std::pair<uint16_t, uint16_t> port_range;
584   std::stringstream ss(flag);
585   char c;
586   ss >> port_range.first;
587   ss.read(&c, 1);
588   ss >> port_range.second;
589   return port_range;
590 }
591 
StrForInstance(const std::string & prefix,int num)592 std::string StrForInstance(const std::string& prefix, int num) {
593   std::ostringstream stream;
594   stream << prefix << std::setfill('0') << std::setw(2) << num;
595   return stream.str();
596 }
597 
GetAndroidInfoConfig(const std::string & android_info_file_path,const std::string & key)598 Result<std::string> GetAndroidInfoConfig(
599     const std::string& android_info_file_path, const std::string& key) {
600   CF_EXPECT(FileExists(android_info_file_path));
601 
602   std::string android_info_contents = ReadFile(android_info_file_path);
603   auto android_info_map = CF_EXPECT(ParseMiscInfo(android_info_contents));
604   CF_EXPECT(android_info_map.find(key) != android_info_map.end());
605   return android_info_map[key];
606 }
607 
608 #ifdef __ANDROID__
ReadGuestConfig()609 Result<std::vector<GuestConfig>> ReadGuestConfig() {
610   std::vector<GuestConfig> rets;
611   auto instance_nums =
612       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
613   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
614     // QEMU isn't on Android, so always follow host arch
615     GuestConfig ret{};
616     ret.target_arch = HostArch();
617     ret.bootconfig_supported = true;
618     ret.android_version_number = "0";
619     rets.push_back(ret);
620   }
621   return rets;
622 }
623 #else
ReadGuestConfig()624 Result<std::vector<GuestConfig>> ReadGuestConfig() {
625   std::vector<GuestConfig> guest_configs;
626   std::vector<std::string> boot_image =
627       android::base::Split(FLAGS_boot_image, ",");
628   std::vector<std::string> kernel_path =
629       android::base::Split(FLAGS_kernel_path, ",");
630   std::vector<std::string> system_image_dir =
631       android::base::Split(FLAGS_system_image_dir, ",");
632   std::string kernel_image_path = "";
633   std::string cur_boot_image;
634   std::string cur_kernel_path;
635 
636   std::string current_path = StringFromEnv("PATH", "");
637   std::string bin_folder = DefaultHostArtifactsPath("bin");
638   std::string new_path = "PATH=";
639   new_path += current_path;
640   new_path += ":";
641   new_path += bin_folder;
642   auto instance_nums =
643       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
644   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
645     // extract-ikconfig can be called directly on the boot image since it looks
646     // for the ikconfig header in the image before extracting the config list.
647     // This code is liable to break if the boot image ever includes the
648     // ikconfig header outside the kernel.
649     cur_kernel_path = "";
650     if (instance_index < kernel_path.size()) {
651       cur_kernel_path = kernel_path[instance_index];
652     }
653 
654     cur_boot_image = "";
655     if (instance_index < boot_image.size()) {
656       cur_boot_image = boot_image[instance_index];
657     }
658 
659     if (cur_kernel_path.size() > 0) {
660       kernel_image_path = cur_kernel_path;
661     } else if (cur_boot_image.size() > 0) {
662       kernel_image_path = cur_boot_image;
663     }
664 
665     GuestConfig guest_config;
666     guest_config.android_version_number = CF_EXPECT(
667         ReadAndroidVersionFromBootImage(FLAGS_early_tmp_dir, cur_boot_image),
668         "Failed to read guest's android version");
669 
670     if (InSandbox()) {
671       // TODO: b/359309462 - real sandboxing for extract-ikconfig
672       guest_config.target_arch = HostArch();
673       guest_config.bootconfig_supported = true;
674       guest_config.hctr2_supported = true;
675     } else {
676       Command ikconfig_cmd(HostBinaryPath("extract-ikconfig"));
677       ikconfig_cmd.AddParameter(kernel_image_path);
678       ikconfig_cmd.UnsetFromEnvironment("PATH").AddEnvironmentVariable(
679           "PATH", new_path);
680       std::string ikconfig_path = FLAGS_early_tmp_dir + "/ikconfig.XXXXXX";
681       auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path);
682       CF_EXPECT(ikconfig_fd->IsOpen(),
683                 "Unable to create ikconfig file: " << ikconfig_fd->StrError());
684       ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut,
685                                  ikconfig_fd);
686 
687       auto ikconfig_proc = ikconfig_cmd.Start();
688       CF_EXPECT(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0,
689                 "Failed to extract ikconfig from " << kernel_image_path);
690 
691       std::string config = ReadFile(ikconfig_path);
692 
693       if (config.find("\nCONFIG_ARM=y") != std::string::npos) {
694         guest_config.target_arch = Arch::Arm;
695       } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) {
696         guest_config.target_arch = Arch::Arm64;
697       } else if (config.find("\nCONFIG_ARCH_RV64I=y") != std::string::npos) {
698         guest_config.target_arch = Arch::RiscV64;
699       } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) {
700         guest_config.target_arch = Arch::X86_64;
701       } else if (config.find("\nCONFIG_X86=y") != std::string::npos) {
702         guest_config.target_arch = Arch::X86;
703       } else {
704         return CF_ERR("Unknown target architecture");
705       }
706       guest_config.bootconfig_supported =
707           config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos;
708       // Once all Cuttlefish kernel versions are at least 5.15, this code can be
709       // removed. CONFIG_CRYPTO_HCTR2=y will always be set.
710       // Note there's also a platform dep for hctr2 introduced in Android 14.
711       // Hence the version check.
712       guest_config.hctr2_supported =
713           (config.find("\nCONFIG_CRYPTO_HCTR2=y") != std::string::npos) &&
714           (guest_config.android_version_number != "11.0.0") &&
715           (guest_config.android_version_number != "13.0.0") &&
716           (guest_config.android_version_number != "11") &&
717           (guest_config.android_version_number != "13");
718 
719       unlink(ikconfig_path.c_str());
720     }
721 
722     std::string instance_android_info_txt;
723     if (instance_index >= system_image_dir.size()) {
724       // in case this is the same image being launhced multiple times
725       // the same flag is used for all instances
726       instance_android_info_txt = system_image_dir[0] + "/android-info.txt";
727     } else {
728       instance_android_info_txt =
729           system_image_dir[instance_index] + "/android-info.txt";
730     }
731 
732     auto res = GetAndroidInfoConfig(instance_android_info_txt, "device_type");
733     // If that "device_type" is not explicitly set, fall back to parse "config".
734     if (!res.ok()) {
735       res = GetAndroidInfoConfig(instance_android_info_txt, "config");
736     }
737     guest_config.device_type = ParseDeviceType(res.value_or(""));
738 
739     res = GetAndroidInfoConfig(instance_android_info_txt, "gfxstream");
740     guest_config.gfxstream_supported =
741         res.ok() && res.value() == "supported";
742 
743     res = GetAndroidInfoConfig(instance_android_info_txt,
744                                "gfxstream_gl_program_binary_link_status");
745     guest_config.gfxstream_gl_program_binary_link_status_supported =
746         res.ok() && res.value() == "supported";
747 
748     auto res_mouse_support =
749         GetAndroidInfoConfig(instance_android_info_txt, "mouse");
750     guest_config.mouse_supported =
751         res_mouse_support.ok() && res_mouse_support.value() == "supported";
752 
753     auto res_custom_keyboard_config =
754         GetAndroidInfoConfig(instance_android_info_txt, "custom_keyboard");
755     if (res_custom_keyboard_config.ok()) {
756       guest_config.custom_keyboard_config =
757           DefaultHostArtifactsPath(res_custom_keyboard_config.value());
758     }
759 
760     auto res_domkey_mapping_config =
761         GetAndroidInfoConfig(instance_android_info_txt, "domkey_mapping");
762     if (res_domkey_mapping_config.ok()) {
763       guest_config.domkey_mapping_config =
764           DefaultHostArtifactsPath(res_domkey_mapping_config.value());
765     }
766 
767     auto res_bgra_support = GetAndroidInfoConfig(instance_android_info_txt,
768                                                  "supports_bgra_framebuffers");
769     guest_config.supports_bgra_framebuffers =
770         res_bgra_support.value_or("") == "true";
771 
772     auto res_vhost_user_vsock =
773         GetAndroidInfoConfig(instance_android_info_txt, "vhost_user_vsock");
774     guest_config.vhost_user_vsock = res_vhost_user_vsock.value_or("") == "true";
775 
776     auto res_prefer_drm_virgl_when_supported = GetAndroidInfoConfig(
777         instance_android_info_txt, "prefer_drm_virgl_when_supported");
778     guest_config.prefer_drm_virgl_when_supported =
779         res_prefer_drm_virgl_when_supported.value_or("") == "true";
780 
781     auto res_ti50_emulator =
782         GetAndroidInfoConfig(instance_android_info_txt, "ti50_emulator");
783     guest_config.ti50_emulator = res_ti50_emulator.value_or("");
784     auto res_output_audio_streams_count = GetAndroidInfoConfig(
785         instance_android_info_txt, "output_audio_streams_count");
786     if (res_output_audio_streams_count.ok()) {
787       std::string output_audio_streams_count_str =
788           res_output_audio_streams_count.value();
789       CF_EXPECT(
790           android::base::ParseInt(output_audio_streams_count_str.c_str(),
791                                   &guest_config.output_audio_streams_count),
792           "Failed to parse value \"" << output_audio_streams_count_str
793                                      << "\" for output audio stream count");
794     }
795 
796     guest_configs.push_back(guest_config);
797   }
798   return guest_configs;
799 }
800 
801 #endif  // #ifdef __ANDROID__
802 
803 template <typename ProtoType>
ParseTextProtoFlagHelper(const std::string & flag_value,const std::string & flag_name)804 Result<ProtoType> ParseTextProtoFlagHelper(const std::string& flag_value,
805                                        const std::string& flag_name) {
806   ProtoType proto_result;
807   google::protobuf::TextFormat::Parser p;
808   CF_EXPECT(p.ParseFromString(flag_value, &proto_result),
809             "Failed to parse: " << flag_name << ", value: " << flag_value);
810   return proto_result;
811 }
812 
813 template <typename ProtoType>
ParseBinProtoFlagHelper(const std::string & flag_value,const std::string & flag_name)814 Result<ProtoType> ParseBinProtoFlagHelper(const std::string& flag_value,
815                                        const std::string& flag_name) {
816   ProtoType proto_result;
817   std::vector<uint8_t> output;
818   CF_EXPECT(DecodeBase64(flag_value, &output));
819   std::string serialized = std::string(output.begin(), output.end());
820   bool result = proto_result.ParseFromString(serialized);
821   CF_EXPECT(proto_result.ParseFromString(serialized),
822             "Failed to parse binary proto, flag: " << flag_name << ", value: "
823                                                    << flag_value);
824   return proto_result;
825 }
826 
827 Result<std::vector<std::vector<CuttlefishConfig::DisplayConfig>>>
ParseDisplaysProto()828     ParseDisplaysProto() {
829   auto proto_result = FLAGS_displays_textproto.empty() ? \
830   ParseBinProtoFlagHelper<InstancesDisplays>(FLAGS_displays_binproto, "displays_binproto") : \
831   ParseTextProtoFlagHelper<InstancesDisplays>(FLAGS_displays_textproto, "displays_textproto");
832 
833   InstancesDisplays display_proto = CF_EXPECT(std::move(proto_result));
834 
835   std::vector<std::vector<CuttlefishConfig::DisplayConfig>> result;
836   for (int i = 0; i < display_proto.instances_size(); i++) {
837     std::vector<CuttlefishConfig::DisplayConfig> display_configs;
838     const InstanceDisplays& launch_cvd_instance = display_proto.instances(i);
839     for (int display_num=0; display_num<launch_cvd_instance.displays_size(); display_num++) {
840       const InstanceDisplay& display = launch_cvd_instance.displays(display_num);
841 
842       // use same code logic from ParseDisplayConfig
843       int display_dpi = CF_DEFAULTS_DISPLAY_DPI;
844       if (display.dpi() != 0) {
845         display_dpi = display.dpi();
846       }
847 
848       int display_refresh_rate_hz = CF_DEFAULTS_DISPLAY_REFRESH_RATE;
849       if (display.refresh_rate_hertz() != 0) {
850         display_refresh_rate_hz = display.refresh_rate_hertz();
851       }
852 
853       std::string overlays = "";
854 
855       for (const auto& overlay : display.overlays()) {
856         overlays +=
857             fmt::format("{}:{} ", overlay.vm_index(), overlay.display_index());
858       }
859 
860       auto dc = CuttlefishConfig::DisplayConfig{
861           .width = display.width(),
862           .height = display.height(),
863           .dpi = display_dpi,
864           .refresh_rate_hz = display_refresh_rate_hz,
865           .overlays = overlays,
866       };
867 
868       display_configs.push_back(dc);
869     }
870     result.push_back(display_configs);
871   }
872 
873   return result;
874 }
875 
CreateNumToWebrtcDeviceIdMap(const CuttlefishConfig & tmp_config_obj,const std::vector<std::int32_t> & instance_nums,const std::string & webrtc_device_id_flag)876 Result<std::unordered_map<int, std::string>> CreateNumToWebrtcDeviceIdMap(
877     const CuttlefishConfig& tmp_config_obj,
878     const std::vector<std::int32_t>& instance_nums,
879     const std::string& webrtc_device_id_flag) {
880   std::unordered_map<int, std::string> output_map;
881   if (webrtc_device_id_flag.empty()) {
882     for (const auto num : instance_nums) {
883       const auto const_instance = tmp_config_obj.ForInstance(num);
884       output_map[num] = const_instance.instance_name();
885     }
886     return output_map;
887   }
888   auto tokens = android::base::Tokenize(webrtc_device_id_flag, ",");
889   CF_EXPECT(tokens.size() == 1 || tokens.size() == instance_nums.size(),
890             "--webrtc_device_ids provided " << tokens.size()
891                                             << " tokens"
892                                                " while 1 or "
893                                             << instance_nums.size()
894                                             << " is expected.");
895   CF_EXPECT(!tokens.empty(), "--webrtc_device_ids is ill-formatted");
896 
897   std::vector<std::string> device_ids;
898   if (tokens.size() != instance_nums.size()) {
899     /* this is only possible when tokens.size() == 1
900      * and instance_nums.size() > 1. The token must include {num}
901      * so that the token pattern can be expanded to multiple instances.
902      */
903     auto device_id = tokens.front();
904     CF_EXPECT(device_id.find("{num}") != std::string::npos,
905               "If one webrtc_device_ids is given for multiple instances, "
906                   << " {num} should be included in webrtc_device_id.");
907     device_ids = std::vector<std::string>(instance_nums.size(), tokens.front());
908   }
909 
910   if (tokens.size() == instance_nums.size()) {
911     // doesn't have to include {num}
912     device_ids = std::move(tokens);
913   }
914 
915   auto itr = device_ids.begin();
916   for (const auto num : instance_nums) {
917     std::string_view device_id_view(itr->data(), itr->size());
918     output_map[num] = android::base::StringReplace(device_id_view, "{num}",
919                                                    std::to_string(num), true);
920     ++itr;
921   }
922   return output_map;
923 }
924 
925 /**
926  * Returns a mapping between flag name and "gflags default_value" as strings for flags
927  * defined in the binary.
928  */
CurrentFlagsToDefaultValue()929 std::map<std::string, std::string> CurrentFlagsToDefaultValue() {
930   std::map<std::string, std::string> name_to_default_value;
931   std::vector<gflags::CommandLineFlagInfo> self_flags;
932   gflags::GetAllFlags(&self_flags);
933   for (auto& flag : self_flags) {
934     name_to_default_value[flag.name] = flag.default_value;
935   }
936   return name_to_default_value;
937 }
938 
GetFlagBoolValueForInstances(const std::string & flag_values,int32_t instances_size,const std::string & flag_name,std::map<std::string,std::string> & name_to_default_value)939 Result<std::vector<bool>> GetFlagBoolValueForInstances(
940     const std::string& flag_values, int32_t instances_size, const std::string& flag_name,
941     std::map<std::string, std::string>& name_to_default_value) {
942   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
943   std::vector<bool> value_vec(instances_size);
944 
945   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
946   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
947 
948   for (int instance_index=0; instance_index<instances_size; instance_index++) {
949     if (instance_index >= flag_vec.size()) {
950       value_vec[instance_index] = CF_EXPECT(ParseBool(flag_vec[0], flag_name));
951     } else {
952       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
953         std::string default_value = default_value_vec[0];
954         if (instance_index < default_value_vec.size()) {
955           default_value = default_value_vec[instance_index];
956         }
957         value_vec[instance_index] = CF_EXPECT(ParseBool(default_value, flag_name));
958       } else {
959         value_vec[instance_index] = CF_EXPECT(ParseBool(flag_vec[instance_index], flag_name));
960       }
961     }
962   }
963   return value_vec;
964 }
965 
GetFlagIntValueForInstances(const std::string & flag_values,int32_t instances_size,const std::string & flag_name,std::map<std::string,std::string> & name_to_default_value)966 Result<std::vector<int>> GetFlagIntValueForInstances(
967     const std::string& flag_values, int32_t instances_size, const std::string& flag_name,
968     std::map<std::string, std::string>& name_to_default_value) {
969   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
970   std::vector<int> value_vec(instances_size);
971 
972   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
973   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
974 
975   for (int instance_index=0; instance_index<instances_size; instance_index++) {
976     if (instance_index >= flag_vec.size()) {
977       CF_EXPECT(android::base::ParseInt(flag_vec[0].c_str(), &value_vec[instance_index]),
978       "Failed to parse value \"" << flag_vec[0] << "\" for " << flag_name);
979     } else {
980       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
981         std::string default_value = default_value_vec[0];
982         if (instance_index < default_value_vec.size()) {
983           default_value = default_value_vec[instance_index];
984         }
985         CF_EXPECT(android::base::ParseInt(default_value,
986         &value_vec[instance_index]),
987         "Failed to parse value \"" << default_value << "\" for " << flag_name);
988       } else {
989         CF_EXPECT(android::base::ParseInt(flag_vec[instance_index].c_str(),
990         &value_vec[instance_index]),
991         "Failed to parse value \"" << flag_vec[instance_index] << "\" for " << flag_name);
992       }
993     }
994   }
995   return value_vec;
996 }
997 
GetFlagStrValueForInstances(const std::string & flag_values,int32_t instances_size,const std::string & flag_name,std::map<std::string,std::string> & name_to_default_value)998 Result<std::vector<std::string>> GetFlagStrValueForInstances(
999     const std::string& flag_values, int32_t instances_size,
1000     const std::string& flag_name, std::map<std::string, std::string>& name_to_default_value) {
1001   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
1002   std::vector<std::string> value_vec(instances_size);
1003 
1004   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
1005   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
1006 
1007   for (int instance_index=0; instance_index<instances_size; instance_index++) {
1008     if (instance_index >= flag_vec.size()) {
1009       value_vec[instance_index] = flag_vec[0];
1010     } else {
1011       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
1012         std::string default_value = default_value_vec[0];
1013         if (instance_index < default_value_vec.size()) {
1014           default_value = default_value_vec[instance_index];
1015         }
1016         value_vec[instance_index] = default_value;
1017       } else {
1018         value_vec[instance_index] = flag_vec[instance_index];
1019       }
1020     }
1021   }
1022   return value_vec;
1023 }
1024 
CheckSnapshotCompatible(const bool must_be_compatible,const std::map<int,std::string> & calculated_gpu_mode)1025 Result<void> CheckSnapshotCompatible(
1026     const bool must_be_compatible,
1027     const std::map<int, std::string>& calculated_gpu_mode) {
1028   if (!must_be_compatible) {
1029     return {};
1030   }
1031 
1032   /*
1033    * TODO(kwstephenkim@): delete this block once virtio-fs is supported
1034    */
1035   CF_EXPECTF(
1036       gflags::GetCommandLineFlagInfoOrDie("enable_virtiofs").current_value ==
1037           "false",
1038       "--enable_virtiofs should be false for snapshot, consider \"{}\"",
1039       "--enable_virtiofs=false");
1040 
1041   /*
1042    * TODO(khei@): delete this block once usb is supported
1043    */
1044   CF_EXPECTF(gflags::GetCommandLineFlagInfoOrDie("enable_usb").current_value ==
1045                  "false",
1046              "--enable_usb should be false for snapshot, consider \"{}\"",
1047              "--enable_usb=false");
1048 
1049   /*
1050    * TODO(kwstephenkim@): delete this block once 3D gpu mode snapshots are
1051    * supported
1052    */
1053   for (const auto& [instance_index, instance_gpu_mode] : calculated_gpu_mode) {
1054     CF_EXPECTF(
1055         instance_gpu_mode == "guest_swiftshader",
1056         "Only 2D guest_swiftshader is supported for snapshot. Consider \"{}\"",
1057         "--gpu_mode=guest_swiftshader");
1058   }
1059   return {};
1060 }
1061 
EnvironmentUdsDir()1062 std::optional<std::string> EnvironmentUdsDir() {
1063   std::string environments_uds_dir =
1064       fmt::format("{}/cf_env_{}", TempDir(), getuid());
1065   if (DirectoryExists(environments_uds_dir) &&
1066       !CanAccess(environments_uds_dir, R_OK | W_OK | X_OK)) {
1067     return std::nullopt;
1068   }
1069   return environments_uds_dir;
1070 }
1071 
InstancesUdsDir()1072 std::optional<std::string> InstancesUdsDir() {
1073   std::string instances_uds_dir =
1074       fmt::format("{}/cf_avd_{}", TempDir(), getuid());
1075   if (DirectoryExists(instances_uds_dir) &&
1076       !CanAccess(instances_uds_dir, R_OK | W_OK | X_OK)) {
1077     return std::nullopt;
1078   }
1079   return instances_uds_dir;
1080 }
1081 
DefaultBootloaderArchDir(Arch arch)1082 std::string DefaultBootloaderArchDir(Arch arch) {
1083   switch (arch) {
1084     case Arch::Arm64:
1085       return "aarch64";
1086     case Arch::Arm:
1087       return "arm";
1088     case Arch::RiscV64:
1089       return "riscv64";
1090     case Arch::X86:
1091     case Arch::X86_64:
1092       return "x86_64";
1093   }
1094 }
1095 
1096 } // namespace
1097 
InitializeCuttlefishConfiguration(const std::string & root_dir,const std::vector<GuestConfig> & guest_configs,fruit::Injector<> & injector,const FetcherConfig & fetcher_config)1098 Result<CuttlefishConfig> InitializeCuttlefishConfiguration(
1099     const std::string& root_dir,
1100     const std::vector<GuestConfig>& guest_configs,
1101     fruit::Injector<>& injector, const FetcherConfig& fetcher_config) {
1102   CuttlefishConfig tmp_config_obj;
1103   // If a snapshot path is provided, do not read all flags to set up the config.
1104   // Instead, read the config that was saved at time of snapshot and restore
1105   // that for this run.
1106   // TODO (khei@/kwstephenkim@): b/310034839
1107   const std::string snapshot_path = FLAGS_snapshot_path;
1108   if (!snapshot_path.empty()) {
1109     const std::string snapshot_path_config =
1110         snapshot_path + "/assembly/cuttlefish_config.json";
1111     tmp_config_obj.LoadFromFile(snapshot_path_config.c_str());
1112     tmp_config_obj.set_snapshot_path(snapshot_path);
1113     return tmp_config_obj;
1114   }
1115 
1116   for (const auto& fragment : injector.getMultibindings<ConfigFragment>()) {
1117     CHECK(tmp_config_obj.SaveFragment(*fragment))
1118         << "Failed to save fragment " << fragment->Name();
1119   }
1120 
1121   tmp_config_obj.set_root_dir(root_dir);
1122 
1123   tmp_config_obj.set_environments_uds_dir(
1124       EnvironmentUdsDir().value_or(tmp_config_obj.environments_dir()));
1125   tmp_config_obj.set_instances_uds_dir(
1126       InstancesUdsDir().value_or(tmp_config_obj.instances_dir()));
1127 
1128   auto instance_nums =
1129       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
1130 
1131   // TODO(weihsu), b/250988697:
1132   // FLAGS_vm_manager used too early, have to handle this vectorized string early
1133   // Currently, all instances should use same vmm, added checking here
1134   std::vector<std::string> vm_manager_vec =
1135       android::base::Split(FLAGS_vm_manager, ",");
1136   for (int i=1; i<vm_manager_vec.size(); i++) {
1137     CF_EXPECT(
1138         vm_manager_vec[0] == vm_manager_vec[i],
1139         "All instances should have same vm_manager, " << FLAGS_vm_manager);
1140   }
1141   CF_EXPECT_GT(vm_manager_vec.size(), 0);
1142   while (vm_manager_vec.size() < instance_nums.size()) {
1143     vm_manager_vec.emplace_back(vm_manager_vec[0]);
1144   }
1145 
1146   // TODO(weihsu), b/250988697: moved bootconfig_supported and hctr2_supported
1147   // into each instance, but target_arch is still in todo
1148   // target_arch should be in instance later
1149   auto vmm_mode = CF_EXPECT(ParseVmm(vm_manager_vec[0]));
1150   auto vmm = GetVmManager(vmm_mode, guest_configs[0].target_arch);
1151   if (!vmm) {
1152     LOG(FATAL) << "Invalid vm_manager: " << vm_manager_vec[0];
1153   }
1154   tmp_config_obj.set_vm_manager(vmm_mode);
1155   tmp_config_obj.set_ap_vm_manager(vm_manager_vec[0] + "_openwrt");
1156 
1157   // TODO: schuffelen - fix behavior on riscv64
1158   if (guest_configs[0].target_arch == Arch::RiscV64) {
1159     static constexpr char kRiscv64Secure[] = "keymint,gatekeeper,oemlock";
1160     SetCommandLineOptionWithMode("secure_hals", kRiscv64Secure,
1161                                  google::FlagSettingMode::SET_FLAGS_DEFAULT);
1162   } else {
1163     static constexpr char kDefaultSecure[] =
1164         "oemlock,guest_keymint_insecure,guest_gatekeeper_insecure";
1165     SetCommandLineOptionWithMode("secure_hals", kDefaultSecure,
1166                                  google::FlagSettingMode::SET_FLAGS_DEFAULT);
1167   }
1168   auto secure_hals = CF_EXPECT(ParseSecureHals(FLAGS_secure_hals));
1169   CF_EXPECT(ValidateSecureHals(secure_hals));
1170   tmp_config_obj.set_secure_hals(secure_hals);
1171 
1172   tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
1173 
1174   if (FLAGS_track_host_tools_crc) {
1175     tmp_config_obj.set_host_tools_version(HostToolsCrc());
1176   }
1177 
1178   tmp_config_obj.set_gem5_debug_flags(FLAGS_gem5_debug_flags);
1179 
1180   // streaming, webrtc setup
1181   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
1182   tmp_config_obj.set_sig_server_secure(FLAGS_webrtc_sig_server_secure);
1183   // Note: This will be overridden if the sig server is started by us
1184   tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
1185   tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
1186   tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
1187   tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
1188 
1189   tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
1190   // TODO(moelsherif): Handle this flag (set_metrics_binary) in the future
1191 
1192 #ifdef ENFORCE_MAC80211_HWSIM
1193   tmp_config_obj.set_virtio_mac80211_hwsim(true);
1194 #else
1195   tmp_config_obj.set_virtio_mac80211_hwsim(false);
1196 #endif
1197 
1198   if ((FLAGS_ap_rootfs_image.empty()) != (FLAGS_ap_kernel_image.empty())) {
1199     LOG(FATAL) << "Either both ap_rootfs_image and ap_kernel_image should be "
1200         "set or neither should be set.";
1201   }
1202   // If user input multiple values, we only take the 1st value and shared with
1203   // all instances
1204   std::string ap_rootfs_image = "";
1205   if (!FLAGS_ap_rootfs_image.empty()) {
1206     ap_rootfs_image = android::base::Split(FLAGS_ap_rootfs_image, ",")[0];
1207   }
1208 
1209   tmp_config_obj.set_ap_rootfs_image(ap_rootfs_image);
1210   tmp_config_obj.set_ap_kernel_image(FLAGS_ap_kernel_image);
1211 
1212   // netsim flags allow all radios or selecting a specific radio
1213   bool is_any_netsim = FLAGS_netsim || FLAGS_netsim_bt || FLAGS_netsim_uwb;
1214   bool is_bt_netsim = FLAGS_netsim || FLAGS_netsim_bt;
1215   bool is_uwb_netsim = FLAGS_netsim || FLAGS_netsim_uwb;
1216 
1217   // crosvm should create fifos for Bluetooth
1218   tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth ||
1219                                            is_bt_netsim);
1220 
1221   // rootcanal and bt_connector should handle Bluetooth (instead of netsim)
1222   tmp_config_obj.set_enable_host_bluetooth_connector(FLAGS_enable_host_bluetooth && !is_bt_netsim);
1223 
1224   tmp_config_obj.set_enable_host_nfc(FLAGS_enable_host_nfc);
1225   tmp_config_obj.set_enable_host_nfc_connector(FLAGS_enable_host_nfc);
1226 
1227   // These flags inform NetsimServer::ResultSetup which radios it owns.
1228   if (is_bt_netsim) {
1229     tmp_config_obj.netsim_radio_enable(CuttlefishConfig::NetsimRadio::Bluetooth);
1230   }
1231   // end of vectorize ap_rootfs_image, ap_kernel_image, wmediumd_config
1232 
1233   tmp_config_obj.set_enable_automotive_proxy(FLAGS_enable_automotive_proxy);
1234 
1235   // get flag default values and store into map
1236   auto name_to_default_value = CurrentFlagsToDefaultValue();
1237   // old flags but vectorized for multi-device instances
1238   int32_t instances_size = instance_nums.size();
1239   std::vector<std::string> gnss_file_paths =
1240       CF_EXPECT(GET_FLAG_STR_VALUE(gnss_file_path));
1241   std::vector<std::string> fixed_location_file_paths =
1242       CF_EXPECT(GET_FLAG_STR_VALUE(fixed_location_file_path));
1243   std::vector<int> x_res_vec = CF_EXPECT(GET_FLAG_INT_VALUE(x_res));
1244   std::vector<int> y_res_vec = CF_EXPECT(GET_FLAG_INT_VALUE(y_res));
1245   std::vector<int> dpi_vec = CF_EXPECT(GET_FLAG_INT_VALUE(dpi));
1246   std::vector<int> refresh_rate_hz_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1247       refresh_rate_hz));
1248   std::vector<std::string> overlays_vec =
1249       CF_EXPECT(GET_FLAG_STR_VALUE(overlays));
1250   std::vector<int> memory_mb_vec = CF_EXPECT(GET_FLAG_INT_VALUE(memory_mb));
1251   std::vector<int> camera_server_port_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1252       camera_server_port));
1253   std::vector<int> vsock_guest_cid_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1254       vsock_guest_cid));
1255   std::vector<std::string> vsock_guest_group_vec =
1256       CF_EXPECT(GET_FLAG_STR_VALUE(vsock_guest_group));
1257   std::vector<int> cpus_vec = CF_EXPECT(GET_FLAG_INT_VALUE(cpus));
1258   std::vector<int> blank_data_image_mb_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1259       blank_data_image_mb));
1260   std::vector<int> gdb_port_vec = CF_EXPECT(GET_FLAG_INT_VALUE(gdb_port));
1261   std::vector<std::string> setupwizard_mode_vec =
1262       CF_EXPECT(GET_FLAG_STR_VALUE(setupwizard_mode));
1263   std::vector<std::string> userdata_format_vec =
1264       CF_EXPECT(GET_FLAG_STR_VALUE(userdata_format));
1265   std::vector<bool> guest_enforce_security_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1266       guest_enforce_security));
1267   std::vector<bool> use_random_serial_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1268       use_random_serial));
1269   std::vector<bool> use_allocd_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_allocd));
1270   std::vector<bool> use_sdcard_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_sdcard));
1271   std::vector<bool> pause_in_bootloader_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1272       pause_in_bootloader));
1273   std::vector<bool> daemon_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(daemon));
1274   std::vector<bool> enable_minimal_mode_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1275       enable_minimal_mode));
1276   std::vector<bool> enable_modem_simulator_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1277       enable_modem_simulator));
1278   std::vector<int> modem_simulator_count_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1279       modem_simulator_count));
1280   std::vector<int> modem_simulator_sim_type_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
1281       modem_simulator_sim_type));
1282   std::vector<bool> console_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(console));
1283   std::vector<bool> enable_audio_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_audio));
1284   std::vector<bool> enable_usb_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_usb));
1285   std::vector<bool> start_gnss_proxy_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1286       start_gnss_proxy));
1287   std::vector<bool> enable_bootanimation_vec =
1288       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_bootanimation));
1289 
1290   std::vector<std::string> extra_bootconfig_args_base64_vec =
1291       CF_EXPECT(GET_FLAG_STR_VALUE(extra_bootconfig_args_base64));
1292 
1293   std::vector<bool> record_screen_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1294       record_screen));
1295   std::vector<std::string> gem5_debug_file_vec =
1296       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_debug_file));
1297   std::vector<bool> protected_vm_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1298       protected_vm));
1299   std::vector<bool> mte_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(mte));
1300   std::vector<bool> enable_kernel_log_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1301       enable_kernel_log));
1302   std::vector<bool> kgdb_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(kgdb));
1303   std::vector<std::string> boot_slot_vec =
1304       CF_EXPECT(GET_FLAG_STR_VALUE(boot_slot));
1305   std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1306       start_webrtc));
1307   std::vector<std::string> webrtc_assets_dir_vec =
1308       CF_EXPECT(GET_FLAG_STR_VALUE(webrtc_assets_dir));
1309   std::vector<std::string> tcp_port_range_vec =
1310       CF_EXPECT(GET_FLAG_STR_VALUE(tcp_port_range));
1311   std::vector<std::string> udp_port_range_vec =
1312       CF_EXPECT(GET_FLAG_STR_VALUE(udp_port_range));
1313   std::vector<bool> vhost_net_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1314       vhost_net));
1315   std::vector<std::string> vhost_user_vsock_vec =
1316       CF_EXPECT(GET_FLAG_STR_VALUE(vhost_user_vsock));
1317   std::vector<std::string> ril_dns_vec =
1318       CF_EXPECT(GET_FLAG_STR_VALUE(ril_dns));
1319 
1320   // At this time, FLAGS_enable_sandbox comes from SetDefaultFlagsForCrosvm
1321   std::vector<bool> enable_sandbox_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1322       enable_sandbox));
1323   std::vector<bool> enable_virtiofs_vec =
1324       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_virtiofs));
1325 
1326   std::vector<std::string> gpu_mode_vec =
1327       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_mode));
1328   std::map<int, std::string> calculated_gpu_mode_vec;
1329   std::vector<std::string> gpu_vhost_user_mode_vec =
1330       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_vhost_user_mode));
1331   std::vector<std::string> gpu_renderer_features_vec =
1332       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_renderer_features));
1333   std::vector<std::string> gpu_context_types_vec =
1334       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_context_types));
1335   std::vector<std::string> guest_hwui_renderer_vec =
1336       CF_EXPECT(GET_FLAG_STR_VALUE(guest_hwui_renderer));
1337   std::vector<std::string> guest_renderer_preload_vec =
1338       CF_EXPECT(GET_FLAG_STR_VALUE(guest_renderer_preload));
1339   std::vector<std::string> guest_vulkan_driver_vec =
1340       CF_EXPECT(GET_FLAG_STR_VALUE(guest_vulkan_driver));
1341   std::vector<std::string> frames_socket_path_vec =
1342       CF_EXPECT(GET_FLAG_STR_VALUE(frames_socket_path));
1343 
1344   std::vector<std::string> gpu_capture_binary_vec =
1345       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_capture_binary));
1346   std::vector<bool> restart_subprocesses_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1347       restart_subprocesses));
1348   std::vector<std::string> hwcomposer_vec =
1349       CF_EXPECT(GET_FLAG_STR_VALUE(hwcomposer));
1350   std::vector<bool> enable_gpu_udmabuf_vec =
1351       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_gpu_udmabuf));
1352   std::vector<bool> smt_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(smt));
1353   std::vector<std::string> crosvm_binary_vec =
1354       CF_EXPECT(GET_FLAG_STR_VALUE(crosvm_binary));
1355   std::vector<std::string> seccomp_policy_dir_vec =
1356       CF_EXPECT(GET_FLAG_STR_VALUE(seccomp_policy_dir));
1357   std::vector<std::string> qemu_binary_dir_vec =
1358       CF_EXPECT(GET_FLAG_STR_VALUE(qemu_binary_dir));
1359 
1360   // new instance specific flags (moved from common flags)
1361   std::vector<std::string> gem5_binary_dir_vec =
1362       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_binary_dir));
1363   std::vector<std::string> gem5_checkpoint_dir_vec =
1364       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_checkpoint_dir));
1365   std::vector<std::string> data_policy_vec =
1366       CF_EXPECT(GET_FLAG_STR_VALUE(data_policy));
1367 
1368   // multi-dv multi-display proto input
1369   std::vector<std::vector<CuttlefishConfig::DisplayConfig>> instances_display_configs;
1370   if (!FLAGS_displays_textproto.empty() || !FLAGS_displays_binproto.empty()) {
1371     instances_display_configs = CF_EXPECT(ParseDisplaysProto());
1372   }
1373 
1374   std::vector<bool> use_balloon_vec =
1375       CF_EXPECT(GET_FLAG_BOOL_VALUE(crosvm_use_balloon));
1376   std::vector<bool> use_rng_vec =
1377       CF_EXPECT(GET_FLAG_BOOL_VALUE(crosvm_use_rng));
1378   std::vector<bool> simple_media_device_vec =
1379       CF_EXPECT(GET_FLAG_BOOL_VALUE(crosvm_simple_media_device));
1380   std::vector<std::string> v4l2_proxy_vec =
1381       CF_EXPECT(GET_FLAG_STR_VALUE(crosvm_v4l2_proxy));
1382   std::vector<bool> use_pmem_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_pmem));
1383   const bool restore_from_snapshot = !std::string(FLAGS_snapshot_path).empty();
1384   std::vector<std::string> device_external_network_vec =
1385       CF_EXPECT(GET_FLAG_STR_VALUE(device_external_network));
1386 
1387   std::vector<bool> fail_fast_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(fail_fast));
1388 
1389   std::vector<bool> vhost_user_block_vec =
1390       CF_EXPECT(GET_FLAG_BOOL_VALUE(vhost_user_block));
1391 
1392   std::vector<std::string> mcu_config_vec = CF_EXPECT(GET_FLAG_STR_VALUE(mcu_config_path));
1393 
1394   std::vector<std::string> vcpu_config_vec =
1395       CF_EXPECT(GET_FLAG_STR_VALUE(vcpu_config_path));
1396 
1397   std::vector<bool> enable_tap_devices_vec =
1398       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_tap_devices));
1399 
1400   std::string default_enable_sandbox = "";
1401   std::string default_enable_virtiofs = "";
1402   std::string comma_str = "";
1403 
1404   CHECK(FLAGS_use_overlay || instance_nums.size() == 1)
1405       << "`--use_overlay=false` is incompatible with multiple instances";
1406   CHECK(instance_nums.size() > 0) << "Require at least one instance.";
1407   auto rootcanal_instance_num = *instance_nums.begin() - 1;
1408   if (FLAGS_rootcanal_instance_num > 0) {
1409     rootcanal_instance_num = FLAGS_rootcanal_instance_num - 1;
1410   }
1411   tmp_config_obj.set_rootcanal_args(FLAGS_rootcanal_args);
1412   tmp_config_obj.set_rootcanal_hci_port(7300 + rootcanal_instance_num);
1413   tmp_config_obj.set_rootcanal_link_port(7400 + rootcanal_instance_num);
1414   tmp_config_obj.set_rootcanal_test_port(7500 + rootcanal_instance_num);
1415   tmp_config_obj.set_rootcanal_link_ble_port(7600 + rootcanal_instance_num);
1416   LOG(DEBUG) << "rootcanal_instance_num: " << rootcanal_instance_num;
1417   LOG(DEBUG) << "launch rootcanal: " << (FLAGS_rootcanal_instance_num <= 0);
1418 
1419   tmp_config_obj.set_casimir_args(FLAGS_casimir_args);
1420   auto casimir_instance_num = *instance_nums.begin() - 1;
1421   if (FLAGS_casimir_instance_num > 0) {
1422     casimir_instance_num = FLAGS_casimir_instance_num - 1;
1423   }
1424   tmp_config_obj.set_casimir_nci_port(7800 + casimir_instance_num);
1425   tmp_config_obj.set_casimir_rf_port(7900 + casimir_instance_num);
1426   LOG(DEBUG) << "casimir_instance_num: " << casimir_instance_num;
1427   LOG(DEBUG) << "launch casimir: " << (FLAGS_casimir_instance_num <= 0);
1428 
1429   int netsim_instance_num = *instance_nums.begin() - 1;
1430   tmp_config_obj.set_netsim_instance_num(netsim_instance_num);
1431   LOG(DEBUG) << "netsim_instance_num: " << netsim_instance_num;
1432   tmp_config_obj.set_netsim_args(FLAGS_netsim_args);
1433   // netsim built-in connector will forward packets to another daemon instance,
1434   // filling the role of bluetooth_connector when is_bt_netsim is true.
1435   auto netsim_connector_instance_num = netsim_instance_num;
1436   if (netsim_instance_num != rootcanal_instance_num) {
1437     netsim_connector_instance_num = rootcanal_instance_num;
1438   }
1439   tmp_config_obj.set_netsim_connector_instance_num(
1440       netsim_connector_instance_num);
1441 
1442   // crosvm should create fifos for UWB
1443   auto pica_instance_num = *instance_nums.begin() - 1;
1444   if (FLAGS_pica_instance_num > 0) {
1445     pica_instance_num = FLAGS_pica_instance_num - 1;
1446   }
1447   tmp_config_obj.set_enable_host_uwb(FLAGS_enable_host_uwb || is_uwb_netsim);
1448 
1449   // netsim has its own connector for uwb
1450   tmp_config_obj.set_enable_host_uwb_connector(FLAGS_enable_host_uwb &&
1451                                                !is_uwb_netsim);
1452 
1453   if (is_uwb_netsim) {
1454     tmp_config_obj.netsim_radio_enable(CuttlefishConfig::NetsimRadio::Uwb);
1455   }
1456 
1457   tmp_config_obj.set_pica_uci_port(7000 + pica_instance_num);
1458   LOG(DEBUG) << "launch pica: " << (FLAGS_pica_instance_num <= 0);
1459 
1460   auto straced = android::base::Tokenize(FLAGS_straced_host_executables, ",");
1461   std::set<std::string> straced_set(straced.begin(), straced.end());
1462   tmp_config_obj.set_straced_host_executables(straced_set);
1463 
1464   auto vhal_proxy_server_instance_num = *instance_nums.begin() - 1;
1465   if (FLAGS_vhal_proxy_server_instance_num > 0) {
1466     vhal_proxy_server_instance_num = FLAGS_vhal_proxy_server_instance_num - 1;
1467   }
1468   tmp_config_obj.set_vhal_proxy_server_port(
1469       cuttlefish::vhal_proxy_server::kDefaultEthPort +
1470       vhal_proxy_server_instance_num);
1471   LOG(DEBUG) << "launch vhal proxy server: "
1472              << (FLAGS_enable_vhal_proxy_server &&
1473                  vhal_proxy_server_instance_num <= 0);
1474 
1475   tmp_config_obj.set_kvm_path(FLAGS_kvm_path);
1476   tmp_config_obj.set_vhost_vsock_path(FLAGS_vhost_vsock_path);
1477 
1478   // Environment specific configs
1479   // Currently just setting for the default environment
1480   auto environment_name =
1481       std::string("env-") + std::to_string(instance_nums[0]);
1482   auto mutable_env_config = tmp_config_obj.ForEnvironment(environment_name);
1483   auto env_config = const_cast<const CuttlefishConfig&>(tmp_config_obj)
1484                         .ForEnvironment(environment_name);
1485 
1486   mutable_env_config.set_group_uuid(std::time(0));
1487 
1488   mutable_env_config.set_enable_wifi(FLAGS_enable_wifi);
1489 
1490   mutable_env_config.set_vhost_user_mac80211_hwsim(
1491       FLAGS_vhost_user_mac80211_hwsim);
1492 
1493   mutable_env_config.set_wmediumd_config(FLAGS_wmediumd_config);
1494 
1495   // Start wmediumd process for the first instance if
1496   // vhost_user_mac80211_hwsim is not specified.
1497   const bool start_wmediumd = tmp_config_obj.virtio_mac80211_hwsim() &&
1498                               FLAGS_vhost_user_mac80211_hwsim.empty() &&
1499                               FLAGS_enable_wifi;
1500   if (start_wmediumd) {
1501     auto vhost_user_socket_path =
1502         env_config.PerEnvironmentUdsPath("vhost_user_mac80211");
1503     auto wmediumd_api_socket_path =
1504         env_config.PerEnvironmentUdsPath("wmediumd_api_server");
1505 
1506     if (instance_nums.size()) {
1507       mutable_env_config.set_wmediumd_mac_prefix(5554);
1508     }
1509     mutable_env_config.set_vhost_user_mac80211_hwsim(vhost_user_socket_path);
1510     mutable_env_config.set_wmediumd_api_server_socket(wmediumd_api_socket_path);
1511 
1512     mutable_env_config.set_start_wmediumd(true);
1513   } else {
1514     mutable_env_config.set_start_wmediumd(false);
1515   }
1516 
1517   const auto graphics_availability =
1518       GetGraphicsAvailabilityWithSubprocessCheck();
1519 
1520   // Instance specific configs
1521   bool is_first_instance = true;
1522   int instance_index = 0;
1523   auto num_to_webrtc_device_id_flag_map =
1524       CF_EXPECT(CreateNumToWebrtcDeviceIdMap(tmp_config_obj, instance_nums,
1525                                              FLAGS_webrtc_device_id));
1526   for (const auto& num : instance_nums) {
1527     IfaceConfig iface_config;
1528     if (use_allocd_vec[instance_index]) {
1529       auto iface_opt = AllocateNetworkInterfaces();
1530       if (!iface_opt.has_value()) {
1531         LOG(FATAL) << "Failed to acquire network interfaces";
1532       }
1533       iface_config = iface_opt.value();
1534     } else {
1535       iface_config = DefaultNetworkInterfaces(num);
1536     }
1537 
1538     auto instance = tmp_config_obj.ForInstance(num);
1539     auto const_instance =
1540         const_cast<const CuttlefishConfig&>(tmp_config_obj).ForInstance(num);
1541 
1542     instance.set_crosvm_use_balloon(use_balloon_vec[instance_index]);
1543     instance.set_crosvm_use_rng(use_rng_vec[instance_index]);
1544     instance.set_crosvm_simple_media_device(simple_media_device_vec[instance_index]);
1545     instance.set_crosvm_v4l2_proxy(v4l2_proxy_vec[instance_index]);
1546     instance.set_use_pmem(use_pmem_vec[instance_index]);
1547     instance.set_bootconfig_supported(guest_configs[instance_index].bootconfig_supported);
1548     instance.set_enable_mouse(guest_configs[instance_index].mouse_supported);
1549     if (guest_configs[instance_index].custom_keyboard_config.has_value()) {
1550       instance.set_custom_keyboard_config(
1551           guest_configs[instance_index].custom_keyboard_config.value());
1552     }
1553     if (guest_configs[instance_index].domkey_mapping_config.has_value()) {
1554       instance.set_domkey_mapping_config(
1555           guest_configs[instance_index].domkey_mapping_config.value());
1556     }
1557     instance.set_filename_encryption_mode(
1558       guest_configs[instance_index].hctr2_supported ? "hctr2" : "cts");
1559     instance.set_use_allocd(use_allocd_vec[instance_index]);
1560     instance.set_enable_audio(enable_audio_vec[instance_index]);
1561     instance.set_enable_usb(enable_usb_vec[instance_index]);
1562     instance.set_enable_gnss_grpc_proxy(start_gnss_proxy_vec[instance_index]);
1563     instance.set_enable_bootanimation(enable_bootanimation_vec[instance_index]);
1564 
1565     instance.set_extra_bootconfig_args(FLAGS_extra_bootconfig_args);
1566     if (!extra_bootconfig_args_base64_vec[instance_index].empty()) {
1567       std::vector<uint8_t> decoded_args;
1568       CF_EXPECT(DecodeBase64(extra_bootconfig_args_base64_vec[instance_index],
1569                              &decoded_args));
1570       std::string decoded_args_str(decoded_args.begin(), decoded_args.end());
1571       instance.set_extra_bootconfig_args(decoded_args_str);
1572     }
1573 
1574     instance.set_record_screen(record_screen_vec[instance_index]);
1575     instance.set_gem5_debug_file(gem5_debug_file_vec[instance_index]);
1576     instance.set_protected_vm(protected_vm_vec[instance_index]);
1577     instance.set_mte(mte_vec[instance_index]);
1578     instance.set_enable_kernel_log(enable_kernel_log_vec[instance_index]);
1579     if (!boot_slot_vec[instance_index].empty()) {
1580       instance.set_boot_slot(boot_slot_vec[instance_index]);
1581     }
1582 
1583     instance.set_crosvm_binary(crosvm_binary_vec[instance_index]);
1584     instance.set_seccomp_policy_dir(seccomp_policy_dir_vec[instance_index]);
1585     instance.set_qemu_binary_dir(qemu_binary_dir_vec[instance_index]);
1586 
1587     // wifi, bluetooth, Thread, connectivity setup
1588 
1589     instance.set_vhost_net(vhost_net_vec[instance_index]);
1590     instance.set_openthread_node_id(num);
1591 
1592     // end of wifi, bluetooth, Thread, connectivity setup
1593 
1594     instance.set_audio_output_streams_count(
1595         guest_configs[instance_index].output_audio_streams_count);
1596 
1597     if (vhost_user_vsock_vec[instance_index] == kVhostUserVsockModeAuto) {
1598       std::set<Arch> default_on_arch = {Arch::Arm64};
1599       if (guest_configs[instance_index].vhost_user_vsock) {
1600         instance.set_vhost_user_vsock(true);
1601       } else if (tmp_config_obj.vm_manager() == VmmMode::kCrosvm &&
1602                  default_on_arch.find(
1603                      guest_configs[instance_index].target_arch) !=
1604                      default_on_arch.end()) {
1605         instance.set_vhost_user_vsock(true);
1606       } else {
1607         instance.set_vhost_user_vsock(false);
1608       }
1609     } else if (vhost_user_vsock_vec[instance_index] ==
1610                kVhostUserVsockModeTrue) {
1611       CHECK(tmp_config_obj.vm_manager() == VmmMode::kCrosvm)
1612           << "For now, only crosvm supports vhost_user_vsock";
1613       instance.set_vhost_user_vsock(true);
1614     } else if (vhost_user_vsock_vec[instance_index] ==
1615                kVhostUserVsockModeFalse) {
1616       instance.set_vhost_user_vsock(false);
1617     } else {
1618       CHECK(false)
1619           << "--vhost_user_vsock should be one of 'auto', 'true', 'false', but "
1620           << vhost_user_vsock_vec[instance_index];
1621     }
1622 
1623     if (use_random_serial_vec[instance_index]) {
1624       instance.set_serial_number(
1625           RandomSerialNumber("CFCVD" + std::to_string(num)));
1626     } else {
1627       instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
1628     }
1629 
1630     instance.set_grpc_socket_path(const_instance.PerInstanceGrpcSocketPath(""));
1631 
1632     // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc
1633     const auto vsock_guest_cid = vsock_guest_cid_vec[instance_index] + num - GetInstance();
1634     instance.set_vsock_guest_cid(vsock_guest_cid);
1635     auto calc_vsock_port = [vsock_guest_cid](const int base_port) {
1636       // a base (vsock) port is like 9600 for modem_simulator, etc
1637       return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid);
1638     };
1639 
1640     const auto vsock_guest_group = vsock_guest_group_vec[instance_index];
1641     instance.set_vsock_guest_group(vsock_guest_group);
1642 
1643     instance.set_session_id(iface_config.mobile_tap.session_id);
1644 
1645     instance.set_cpus(cpus_vec[instance_index]);
1646     // make sure all instances have multiple of 2 then SMT mode
1647     // if any of instance doesn't have multiple of 2 then NOT SMT
1648     CF_EXPECT(!smt_vec[instance_index] || cpus_vec[instance_index] % 2 == 0,
1649               "CPUs must be a multiple of 2 in SMT mode");
1650     instance.set_smt(smt_vec[instance_index]);
1651 
1652     // new instance specific flags (moved from common flags)
1653     CF_EXPECT(instance_index < guest_configs.size(),
1654               "instance_index " << instance_index << " out of boundary "
1655                                 << guest_configs.size());
1656     instance.set_target_arch(guest_configs[instance_index].target_arch);
1657     instance.set_device_type(guest_configs[instance_index].device_type);
1658     instance.set_guest_android_version(
1659         guest_configs[instance_index].android_version_number);
1660     instance.set_console(console_vec[instance_index]);
1661     instance.set_kgdb(console_vec[instance_index] && kgdb_vec[instance_index]);
1662     instance.set_blank_data_image_mb(blank_data_image_mb_vec[instance_index]);
1663     instance.set_gdb_port(gdb_port_vec[instance_index]);
1664     instance.set_fail_fast(fail_fast_vec[instance_index]);
1665     if (vhost_user_block_vec[instance_index]) {
1666       CF_EXPECT_EQ(tmp_config_obj.vm_manager(), VmmMode::kCrosvm,
1667                    "vhost-user block only supported on crosvm");
1668     }
1669     instance.set_vhost_user_block(vhost_user_block_vec[instance_index]);
1670 
1671     std::optional<std::vector<CuttlefishConfig::DisplayConfig>>
1672         binding_displays_configs;
1673     auto displays_configs_bindings =
1674         injector.getMultibindings<DisplaysConfigs>();
1675     CF_EXPECT_EQ(displays_configs_bindings.size(), 1,
1676                  "Expected a single binding?");
1677     if (auto configs = displays_configs_bindings[0]->GetConfigs();
1678         !configs.empty()) {
1679       binding_displays_configs = configs;
1680     }
1681 
1682     std::vector<CuttlefishConfig::DisplayConfig> display_configs;
1683     // assume displays proto input has higher priority than original display inputs
1684     if (!FLAGS_displays_textproto.empty() || !FLAGS_displays_binproto.empty()) {
1685       if (instance_index < instances_display_configs.size()) {
1686         display_configs = instances_display_configs[instance_index];
1687       } // else display_configs is an empty vector
1688     } else if (binding_displays_configs) {
1689       display_configs = *binding_displays_configs;
1690     }
1691 
1692     if (x_res_vec[instance_index] > 0 && y_res_vec[instance_index] > 0) {
1693       if (display_configs.empty()) {
1694         display_configs.push_back({
1695             .width = x_res_vec[instance_index],
1696             .height = y_res_vec[instance_index],
1697             .dpi = dpi_vec[instance_index],
1698             .refresh_rate_hz = refresh_rate_hz_vec[instance_index],
1699             .overlays = overlays_vec[instance_index],
1700         });
1701       } else {
1702         LOG(WARNING)
1703             << "Ignoring --x_res and --y_res when --display specified.";
1704       }
1705     }
1706     instance.set_display_configs(display_configs);
1707 
1708     auto touchpad_configs_bindings =
1709         injector.getMultibindings<TouchpadsConfigs>();
1710     CF_EXPECT_EQ(touchpad_configs_bindings.size(), 1,
1711                  "Expected a single binding?");
1712     auto touchpad_configs = touchpad_configs_bindings[0]->GetConfigs();
1713     instance.set_touchpad_configs(touchpad_configs);
1714 
1715     instance.set_memory_mb(memory_mb_vec[instance_index]);
1716     instance.set_ddr_mem_mb(memory_mb_vec[instance_index] * 1.2);
1717     CF_EXPECT(
1718         instance.set_setupwizard_mode(setupwizard_mode_vec[instance_index]));
1719     instance.set_userdata_format(userdata_format_vec[instance_index]);
1720     instance.set_guest_enforce_security(guest_enforce_security_vec[instance_index]);
1721     instance.set_pause_in_bootloader(pause_in_bootloader_vec[instance_index]);
1722     instance.set_run_as_daemon(daemon_vec[instance_index]);
1723     instance.set_enable_modem_simulator(enable_modem_simulator_vec[instance_index] &&
1724                                         !enable_minimal_mode_vec[instance_index]);
1725     instance.set_modem_simulator_instance_number(modem_simulator_count_vec[instance_index]);
1726     instance.set_modem_simulator_sim_type(modem_simulator_sim_type_vec[instance_index]);
1727 
1728     instance.set_enable_minimal_mode(enable_minimal_mode_vec[instance_index]);
1729     instance.set_camera_server_port(camera_server_port_vec[instance_index]);
1730     instance.set_gem5_binary_dir(gem5_binary_dir_vec[instance_index]);
1731     instance.set_gem5_checkpoint_dir(gem5_checkpoint_dir_vec[instance_index]);
1732     instance.set_data_policy(data_policy_vec[instance_index]);
1733 
1734     instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
1735     instance.set_wifi_bridge_name("cvd-wbr");
1736     instance.set_ethernet_bridge_name("cvd-ebr");
1737     instance.set_mobile_tap_name(iface_config.mobile_tap.name);
1738 
1739     CF_EXPECT(ConfigureNetworkSettings(ril_dns_vec[instance_index],
1740                                        const_instance, instance));
1741 
1742     if (NetworkInterfaceExists(iface_config.non_bridged_wireless_tap.name) &&
1743         tmp_config_obj.virtio_mac80211_hwsim()) {
1744       instance.set_use_bridged_wifi_tap(false);
1745       instance.set_wifi_tap_name(iface_config.non_bridged_wireless_tap.name);
1746     } else {
1747       instance.set_use_bridged_wifi_tap(true);
1748       instance.set_wifi_tap_name(iface_config.bridged_wireless_tap.name);
1749     }
1750 
1751     instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
1752 
1753     instance.set_uuid(FLAGS_uuid);
1754 
1755     instance.set_environment_name(environment_name);
1756 
1757     instance.set_modem_simulator_host_id(1000 + num);  // Must be 4 digits
1758     // the deprecated vnc was 6444 + num - 1, and qemu_vnc was vnc - 5900
1759     instance.set_qemu_vnc_server_port(544 + num - 1);
1760     instance.set_adb_host_port(6520 + num - 1);
1761     instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
1762     instance.set_fastboot_host_port(const_instance.adb_host_port());
1763 
1764     std::uint8_t ethernet_mac[6] = {};
1765     std::uint8_t mobile_mac[6] = {};
1766     std::uint8_t wifi_mac[6] = {};
1767     std::uint8_t ethernet_ipv6[16] = {};
1768     GenerateEthMacForInstance(num - 1, ethernet_mac);
1769     GenerateMobileMacForInstance(num - 1, mobile_mac);
1770     GenerateWifiMacForInstance(num - 1, wifi_mac);
1771     GenerateCorrespondingIpv6ForMac(ethernet_mac, ethernet_ipv6);
1772 
1773     instance.set_ethernet_mac(MacAddressToString(ethernet_mac));
1774     instance.set_mobile_mac(MacAddressToString(mobile_mac));
1775     instance.set_wifi_mac(MacAddressToString(wifi_mac));
1776     instance.set_ethernet_ipv6(Ipv6ToString(ethernet_ipv6));
1777 
1778     instance.set_tombstone_receiver_port(calc_vsock_port(6600));
1779     instance.set_audiocontrol_server_port(
1780         9410); /* OK to use the same port number across instances */
1781     instance.set_lights_server_port(calc_vsock_port(6900));
1782 
1783     // gpu related settings
1784     const std::string gpu_mode = CF_EXPECT(ConfigureGpuSettings(
1785         graphics_availability, gpu_mode_vec[instance_index],
1786         gpu_vhost_user_mode_vec[instance_index],
1787         gpu_renderer_features_vec[instance_index],
1788         gpu_context_types_vec[instance_index],
1789         guest_hwui_renderer_vec[instance_index],
1790         guest_renderer_preload_vec[instance_index], vmm_mode,
1791         guest_configs[instance_index], instance));
1792     calculated_gpu_mode_vec[instance_index] = gpu_mode_vec[instance_index];
1793 
1794     instance.set_restart_subprocesses(restart_subprocesses_vec[instance_index]);
1795     instance.set_gpu_capture_binary(gpu_capture_binary_vec[instance_index]);
1796     if (!gpu_capture_binary_vec[instance_index].empty()) {
1797       CF_EXPECT(gpu_mode == kGpuModeGfxstream ||
1798                     gpu_mode == kGpuModeGfxstreamGuestAngle,
1799                 "GPU capture only supported with --gpu_mode=gfxstream");
1800 
1801       // GPU capture runs in a detached mode where the "launcher" process
1802       // intentionally exits immediately.
1803       CF_EXPECT(!restart_subprocesses_vec[instance_index],
1804           "GPU capture only supported with --norestart_subprocesses");
1805     }
1806 
1807     instance.set_hwcomposer(hwcomposer_vec[instance_index]);
1808     if (!hwcomposer_vec[instance_index].empty()) {
1809       if (hwcomposer_vec[instance_index] == kHwComposerRanchu) {
1810         CF_EXPECT(gpu_mode != kGpuModeDrmVirgl,
1811                   "ranchu hwcomposer not supported with --gpu_mode=drm_virgl");
1812       }
1813     }
1814 
1815     if (hwcomposer_vec[instance_index] == kHwComposerAuto) {
1816       if (gpu_mode == kGpuModeDrmVirgl) {
1817         instance.set_hwcomposer(kHwComposerDrm);
1818       } else if (gpu_mode == kGpuModeNone) {
1819         instance.set_hwcomposer(kHwComposerNone);
1820       } else {
1821         instance.set_hwcomposer(kHwComposerRanchu);
1822       }
1823     }
1824 
1825     instance.set_enable_gpu_udmabuf(enable_gpu_udmabuf_vec[instance_index]);
1826 
1827     instance.set_gpu_context_types(gpu_context_types_vec[instance_index]);
1828     instance.set_guest_vulkan_driver(guest_vulkan_driver_vec[instance_index]);
1829 
1830     instance.set_guest_uses_bgra_framebuffers(
1831         guest_configs[instance_index].supports_bgra_framebuffers);
1832 
1833     if (!frames_socket_path_vec[instance_index].empty()) {
1834       instance.set_frames_socket_path(frames_socket_path_vec[instance_index]);
1835     } else {
1836       instance.set_frames_socket_path(
1837           const_instance.PerInstanceInternalUdsPath("frames.sock"));
1838     }
1839 
1840     // 1. Keep original code order SetCommandLineOptionWithMode("enable_sandbox")
1841     // then set_enable_sandbox later.
1842     // 2. SetCommandLineOptionWithMode condition: if gpu_mode or console,
1843     // then SetCommandLineOptionWithMode false as original code did,
1844     // otherwise keep default enable_sandbox value.
1845     // 3. Sepolicy rules need to be updated to support gpu mode. Temporarily disable
1846     // auto-enabling sandbox when gpu is enabled (b/152323505).
1847     default_enable_sandbox += comma_str;
1848     default_enable_virtiofs += comma_str;
1849     if (gpu_mode != kGpuModeGuestSwiftshader) {
1850       // original code, just moved to each instance setting block
1851       default_enable_sandbox += "false";
1852       default_enable_virtiofs += "false";
1853     } else {
1854       default_enable_sandbox +=
1855           fmt::format("{}", enable_sandbox_vec[instance_index]);
1856       default_enable_virtiofs +=
1857           fmt::format("{}", enable_virtiofs_vec[instance_index]);
1858     }
1859     comma_str = ",";
1860 
1861     CF_EXPECT(vmm->ConfigureGraphics(const_instance));
1862 
1863     // end of gpu related settings
1864 
1865     instance.set_gnss_grpc_proxy_server_port(7200 + num -1);
1866     instance.set_gnss_file_path(gnss_file_paths[instance_index]);
1867     instance.set_fixed_location_file_path(fixed_location_file_paths[instance_index]);
1868 
1869     std::vector<std::string> virtual_disk_paths;
1870 
1871     bool os_overlay = true;
1872     os_overlay &= !protected_vm_vec[instance_index];
1873     // Gem5 already uses CoW wrappers around disk images
1874     os_overlay &= vmm_mode != VmmMode::kGem5;
1875     os_overlay &= FLAGS_use_overlay;
1876     if (os_overlay) {
1877       auto path = const_instance.PerInstancePath("overlay.img");
1878       virtual_disk_paths.push_back(path);
1879     } else {
1880       virtual_disk_paths.push_back(const_instance.os_composite_disk_path());
1881     }
1882 
1883     bool persistent_disk = true;
1884     persistent_disk &= !protected_vm_vec[instance_index];
1885     persistent_disk &= vmm_mode != VmmMode::kGem5;
1886     if (persistent_disk) {
1887 #ifdef __APPLE__
1888       const std::string persistent_composite_img_base =
1889           "persistent_composite.img";
1890 #else
1891       const bool is_vm_qemu_cli =
1892           (tmp_config_obj.vm_manager() == VmmMode::kQemu);
1893       const std::string persistent_composite_img_base =
1894           is_vm_qemu_cli ? "persistent_composite_overlay.img"
1895                          : "persistent_composite.img";
1896 #endif
1897       auto path =
1898           const_instance.PerInstancePath(persistent_composite_img_base.data());
1899       virtual_disk_paths.push_back(path);
1900     }
1901 
1902     instance.set_use_sdcard(use_sdcard_vec[instance_index]);
1903 
1904     bool sdcard = true;
1905     sdcard &= use_sdcard_vec[instance_index];
1906     sdcard &= !protected_vm_vec[instance_index];
1907     if (sdcard) {
1908       if (tmp_config_obj.vm_manager() == VmmMode::kQemu) {
1909         virtual_disk_paths.push_back(const_instance.sdcard_overlay_path());
1910       } else {
1911         virtual_disk_paths.push_back(const_instance.sdcard_path());
1912       }
1913     }
1914 
1915     instance.set_virtual_disk_paths(virtual_disk_paths);
1916 
1917     // We'd like to set mac prefix to be 5554, 5555, 5556, ... in normal cases.
1918     // When --base_instance_num=3, this might be 5556, 5557, 5558, ... (skipping
1919     // first two)
1920     instance.set_wifi_mac_prefix(5554 + (num - 1));
1921 
1922     // streaming, webrtc setup
1923     instance.set_enable_webrtc(start_webrtc_vec[instance_index]);
1924     instance.set_webrtc_assets_dir(webrtc_assets_dir_vec[instance_index]);
1925 
1926     auto tcp_range  = ParsePortRange(tcp_port_range_vec[instance_index]);
1927     instance.set_webrtc_tcp_port_range(tcp_range);
1928 
1929     auto udp_range  = ParsePortRange(udp_port_range_vec[instance_index]);
1930     instance.set_webrtc_udp_port_range(udp_range);
1931 
1932     // end of streaming, webrtc setup
1933 
1934     instance.set_start_webrtc_signaling_server(false);
1935 
1936     CF_EXPECT(Contains(num_to_webrtc_device_id_flag_map, num),
1937               "Error in looking up num to webrtc_device_id_flag_map");
1938     instance.set_webrtc_device_id(num_to_webrtc_device_id_flag_map[num]);
1939 
1940     instance.set_group_id(FLAGS_group_id);
1941 
1942     if (!is_first_instance || !start_webrtc_vec[instance_index]) {
1943       // Only the first instance starts the signaling server or proxy
1944       instance.set_start_webrtc_signaling_server(false);
1945       instance.set_start_webrtc_sig_server_proxy(false);
1946     } else {
1947       auto port = 8443 + num - 1;
1948       // Change the signaling server port for all instances
1949       tmp_config_obj.set_sig_server_port(port);
1950       // Either the signaling server or the proxy is started, never both
1951       instance.set_start_webrtc_signaling_server(FLAGS_start_webrtc_sig_server);
1952       // The proxy is only started if the host operator is available
1953       instance.set_start_webrtc_sig_server_proxy(
1954           cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH) &&
1955           !FLAGS_start_webrtc_sig_server);
1956     }
1957 
1958     instance.set_start_netsim(is_first_instance && is_any_netsim);
1959 
1960     instance.set_start_rootcanal(is_first_instance && !is_bt_netsim &&
1961                                  (FLAGS_rootcanal_instance_num <= 0));
1962 
1963     instance.set_start_casimir(is_first_instance && FLAGS_casimir_instance_num <= 0);
1964 
1965     instance.set_start_pica(is_first_instance && !is_uwb_netsim &&
1966                             FLAGS_pica_instance_num <= 0);
1967     instance.set_start_vhal_proxy_server(
1968         is_first_instance && FLAGS_enable_vhal_proxy_server &&
1969         FLAGS_vhal_proxy_server_instance_num <= 0);
1970 
1971     // TODO(b/288987294) Remove this when separating environment is done
1972     bool instance_start_wmediumd = is_first_instance && start_wmediumd;
1973     instance.set_start_wmediumd_instance(instance_start_wmediumd);
1974 
1975     if (!FLAGS_ap_rootfs_image.empty() && !FLAGS_ap_kernel_image.empty() &&
1976         const_instance.start_wmediumd_instance()) {
1977       // TODO(264537774): Ubuntu grub modules / grub monoliths cannot be used to boot
1978       // 64 bit kernel using 32 bit u-boot / grub.
1979       // Enable this code back after making sure it works across all popular environments
1980       // if (CanGenerateEsp(guest_configs[0].target_arch)) {
1981       //   instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::Grub);
1982       // } else {
1983       //   instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::LegacyDirect);
1984       // }
1985       instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::LegacyDirect);
1986     } else {
1987       instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::None);
1988     }
1989 
1990     is_first_instance = false;
1991 
1992     // instance.modem_simulator_ports := "" or "[port,]*port"
1993     if (modem_simulator_count_vec[instance_index] > 0) {
1994       std::stringstream modem_ports;
1995       for (auto index {0}; index < modem_simulator_count_vec[instance_index] - 1; index++) {
1996         auto port = 9600 + (modem_simulator_count_vec[instance_index] * (num - 1)) + index;
1997         modem_ports << calc_vsock_port(port) << ",";
1998       }
1999       auto port = 9600 + (modem_simulator_count_vec[instance_index] * (num - 1)) +
2000                   modem_simulator_count_vec[instance_index] - 1;
2001       modem_ports << calc_vsock_port(port);
2002       instance.set_modem_simulator_ports(modem_ports.str());
2003     } else {
2004       instance.set_modem_simulator_ports("");
2005     }
2006 
2007     auto external_network_mode = CF_EXPECT(
2008         ParseExternalNetworkMode(device_external_network_vec[instance_index]));
2009     CF_EXPECT(external_network_mode == ExternalNetworkMode::kTap ||
2010                   vmm_mode == VmmMode::kQemu,
2011               "TODO(b/286284441): slirp only works on QEMU");
2012     instance.set_external_network_mode(external_network_mode);
2013 
2014     if (!mcu_config_vec[instance_index].empty()) {
2015       auto mcu_cfg_path = mcu_config_vec[instance_index];
2016       CF_EXPECT(FileExists(mcu_cfg_path), "MCU config file does not exist");
2017       std::string file_content;
2018       using android::base::ReadFileToString;
2019       CF_EXPECT(ReadFileToString(mcu_cfg_path.c_str(), &file_content,
2020                                  /* follow_symlinks */ true),
2021                 "Failed to read mcu config file");
2022       instance.set_mcu(CF_EXPECT(ParseJson(file_content), "Failed parsing JSON file"));
2023     }
2024 
2025     if (!vcpu_config_vec[instance_index].empty()) {
2026       auto vcpu_cfg_path = vcpu_config_vec[instance_index];
2027       CF_EXPECT(FileExists(vcpu_cfg_path), "vCPU config file does not exist");
2028       instance.set_vcpu_config_path(AbsolutePath(vcpu_cfg_path));
2029     }
2030 
2031     if (!guest_configs[instance_index].ti50_emulator.empty()) {
2032       auto ti50_emulator =
2033           DefaultHostArtifactsPath(guest_configs[instance_index].ti50_emulator);
2034       CF_EXPECT(FileExists(ti50_emulator),
2035                 "ti50 emulator binary does not exist");
2036       instance.set_ti50_emulator(ti50_emulator);
2037     }
2038 
2039     instance.set_enable_tap_devices(enable_tap_devices_vec[instance_index]);
2040 
2041     instance_index++;
2042   }  // end of num_instances loop
2043 
2044   std::vector<std::string> names;
2045   names.reserve(tmp_config_obj.Instances().size());
2046   for (const auto& instance : tmp_config_obj.Instances()) {
2047     names.emplace_back(instance.instance_name());
2048   }
2049   tmp_config_obj.set_instance_names(names);
2050 
2051   // keep legacy values for acloud or other related tools (b/262284453)
2052   tmp_config_obj.set_crosvm_binary(crosvm_binary_vec[0]);
2053 
2054   // Keep the original code here to set enable_sandbox commandline flag value
2055   SetCommandLineOptionWithMode("enable_sandbox", default_enable_sandbox.c_str(),
2056                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
2057 
2058   // Set virtiofs to match enable_sandbox as it did before adding
2059   // enable_virtiofs flag.
2060   SetCommandLineOptionWithMode("enable_virtiofs",
2061                                default_enable_sandbox.c_str(),
2062                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
2063 
2064   // After SetCommandLineOptionWithMode,
2065   // default flag values changed, need recalculate name_to_default_value
2066   name_to_default_value = CurrentFlagsToDefaultValue();
2067   // After last SetCommandLineOptionWithMode, we could set these special flags
2068   enable_sandbox_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
2069       enable_sandbox));
2070   enable_virtiofs_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_virtiofs));
2071 
2072   instance_index = 0;
2073   for (const auto& num : instance_nums) {
2074     auto instance = tmp_config_obj.ForInstance(num);
2075     instance.set_enable_sandbox(enable_sandbox_vec[instance_index]);
2076     instance.set_enable_virtiofs(enable_virtiofs_vec[instance_index]);
2077     instance_index++;
2078   }
2079 
2080   const auto& environment_specific =
2081       (static_cast<const CuttlefishConfig&>(tmp_config_obj))
2082           .ForEnvironment(environment_name);
2083   CF_EXPECT(CheckSnapshotCompatible(
2084                 FLAGS_snapshot_compatible &&
2085                     (tmp_config_obj.vm_manager() == VmmMode::kCrosvm) &&
2086                     instance_nums.size() == 1,
2087                 calculated_gpu_mode_vec),
2088             "The set of flags is incompatible with snapshot");
2089 
2090   CF_EXPECT(DiskImageFlagsVectorization(tmp_config_obj, fetcher_config));
2091 
2092   return tmp_config_obj;
2093 }
2094 
SetDefaultFlagsForQemu(const std::vector<GuestConfig> & guest_configs,std::map<std::string,std::string> & name_to_default_value)2095 Result<void> SetDefaultFlagsForQemu(
2096     const std::vector<GuestConfig>& guest_configs,
2097     std::map<std::string, std::string>& name_to_default_value) {
2098   auto instance_nums =
2099       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
2100   int32_t instances_size = instance_nums.size();
2101   std::vector<std::string> gpu_mode_vec =
2102       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_mode));
2103   std::vector<bool> start_webrtc_vec =
2104       CF_EXPECT(GET_FLAG_BOOL_VALUE(start_webrtc));
2105   std::vector<std::string> system_image_dir =
2106       CF_EXPECT(GET_FLAG_STR_VALUE(system_image_dir));
2107   std::string curr_bootloader = "";
2108   std::string curr_android_efi_loader = "";
2109   std::string default_bootloader = "";
2110   std::string default_android_efi_loader = "";
2111   std::string default_start_webrtc = "";
2112 
2113   for (int instance_index = 0; instance_index < instance_nums.size();
2114        instance_index++) {
2115     if (instance_index >= system_image_dir.size()) {
2116       curr_bootloader = system_image_dir[0];
2117       curr_android_efi_loader = system_image_dir[0];
2118     } else {
2119       curr_bootloader = system_image_dir[instance_index];
2120       curr_android_efi_loader = system_image_dir[instance_index];
2121     }
2122     curr_bootloader += "/bootloader";
2123     curr_android_efi_loader += "/android_efi_loader.efi";
2124 
2125     // /bootloader isn't presented in the output folder by default and can be
2126     // only fetched by --bootloader in fetch_cvd, so pick it only in case
2127     // it's presented.
2128     if (!FileExists(curr_bootloader)) {
2129       // Fallback to default bootloader
2130       curr_bootloader = DefaultHostArtifactsPath(std::format(
2131           "etc/bootloader_{}/bootloader.qemu",
2132           DefaultBootloaderArchDir(guest_configs[instance_index].target_arch)));
2133     }
2134 
2135     if (instance_index > 0) {
2136       default_bootloader += ",";
2137       default_android_efi_loader += ",";
2138       default_start_webrtc += ",";
2139     }
2140 
2141     default_bootloader += curr_bootloader;
2142     // EFI loader isn't presented in the output folder by default and can be
2143     // only fetched by --uefi_app_build in fetch_cvd, so pick it only in case
2144     // it's presented.
2145     if (FileExists(curr_android_efi_loader)) {
2146       default_android_efi_loader += curr_android_efi_loader;
2147     }
2148     if (gpu_mode_vec[instance_index] == kGpuModeGuestSwiftshader &&
2149         !start_webrtc_vec[instance_index]) {
2150       // This makes WebRTC the default streamer unless the user requests
2151       // another via a --star_<streamer> flag, while at the same time it's
2152       // possible to run without any streamer by setting --start_webrtc=false.
2153       default_start_webrtc += "true";
2154     } else {
2155       default_start_webrtc +=
2156           fmt::format("{}", start_webrtc_vec[instance_index]);
2157     }
2158   }
2159   // This is the 1st place to set "start_webrtc" flag value
2160   // for now, we don't set non-default options for QEMU
2161   SetCommandLineOptionWithMode("start_webrtc", default_start_webrtc.c_str(),
2162                                SET_FLAGS_DEFAULT);
2163 
2164   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
2165                                SET_FLAGS_DEFAULT);
2166   SetCommandLineOptionWithMode("android_efi_loader",
2167                                default_android_efi_loader.c_str(),
2168                                SET_FLAGS_DEFAULT);
2169   return {};
2170 }
2171 
SetDefaultFlagsForCrosvm(const std::vector<GuestConfig> & guest_configs,std::map<std::string,std::string> & name_to_default_value)2172 Result<void> SetDefaultFlagsForCrosvm(
2173     const std::vector<GuestConfig>& guest_configs,
2174     std::map<std::string, std::string>& name_to_default_value) {
2175   auto instance_nums =
2176       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
2177   int32_t instances_size = instance_nums.size();
2178   std::vector<bool> start_webrtc_vec =
2179       CF_EXPECT(GET_FLAG_BOOL_VALUE(start_webrtc));
2180   std::string default_start_webrtc = "";
2181 
2182   std::set<Arch> supported_archs{Arch::X86_64};
2183   bool default_enable_sandbox =
2184       supported_archs.find(HostArch()) != supported_archs.end() &&
2185       EnsureDirectoryExists(kCrosvmVarEmptyDir).ok() &&
2186       IsDirectoryEmpty(kCrosvmVarEmptyDir) && !IsRunningInContainer();
2187 
2188   std::vector<std::string> system_image_dir =
2189       CF_EXPECT(GET_FLAG_STR_VALUE(system_image_dir));
2190   std::string curr_android_efi_loader = "";
2191   std::string curr_bootloader = "";
2192   std::string default_android_efi_loader = "";
2193   std::string default_bootloader = "";
2194   std::string default_enable_sandbox_str = "";
2195   for (int instance_index = 0; instance_index < instance_nums.size();
2196        instance_index++) {
2197     if (instance_index >= system_image_dir.size()) {
2198       curr_bootloader = system_image_dir[0];
2199       curr_android_efi_loader = system_image_dir[0];
2200     } else {
2201       curr_bootloader = system_image_dir[instance_index];
2202       curr_android_efi_loader = system_image_dir[instance_index];
2203     }
2204     curr_bootloader += "/bootloader";
2205     curr_android_efi_loader += "/android_efi_loader.efi";
2206 
2207     // /bootloader isn't presented in the output folder by default and can be
2208     // only fetched by --bootloader in fetch_cvd, so pick it only in case
2209     // it's presented.
2210     if (!FileExists(curr_bootloader)) {
2211       // Fallback to default bootloader
2212       curr_bootloader = DefaultHostArtifactsPath(std::format(
2213           "etc/bootloader_{}/bootloader.crosvm",
2214           DefaultBootloaderArchDir(guest_configs[instance_index].target_arch)));
2215     }
2216 
2217     if (instance_index > 0) {
2218       default_bootloader += ",";
2219       default_android_efi_loader += ",";
2220       default_enable_sandbox_str += ",";
2221       default_start_webrtc += ",";
2222     }
2223 
2224     default_bootloader += curr_bootloader;
2225     // EFI loader isn't presented in the output folder by default and can be
2226     // only fetched by --uefi_app_build in fetch_cvd, so pick it only in case
2227     // it's presented.
2228     if (FileExists(curr_android_efi_loader)) {
2229       default_android_efi_loader += curr_android_efi_loader;
2230     }
2231     default_enable_sandbox_str += fmt::format("{}", default_enable_sandbox);
2232     if (!start_webrtc_vec[instance_index]) {
2233       // This makes WebRTC the default streamer unless the user requests
2234       // another via a --star_<streamer> flag, while at the same time it's
2235       // possible to run without any streamer by setting --start_webrtc=false.
2236       default_start_webrtc += "true";
2237     } else {
2238       default_start_webrtc +=
2239           fmt::format("{}", start_webrtc_vec[instance_index]);
2240     }
2241   }
2242   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
2243                                SET_FLAGS_DEFAULT);
2244   SetCommandLineOptionWithMode("android_efi_loader",
2245                                default_android_efi_loader.c_str(),
2246                                SET_FLAGS_DEFAULT);
2247   // This is the 1st place to set "start_webrtc" flag value
2248   SetCommandLineOptionWithMode("start_webrtc", default_start_webrtc.c_str(),
2249                                SET_FLAGS_DEFAULT);
2250   // This is the 1st place to set "enable_sandbox" flag value
2251   SetCommandLineOptionWithMode(
2252       "enable_sandbox", default_enable_sandbox_str.c_str(), SET_FLAGS_DEFAULT);
2253   SetCommandLineOptionWithMode(
2254       "enable_virtiofs", default_enable_sandbox_str.c_str(), SET_FLAGS_DEFAULT);
2255   return {};
2256 }
2257 
SetDefaultFlagsForGem5()2258 void SetDefaultFlagsForGem5() {
2259   // TODO: Add support for gem5 gpu models
2260   SetCommandLineOptionWithMode("gpu_mode", kGpuModeGuestSwiftshader,
2261                                SET_FLAGS_DEFAULT);
2262 
2263   SetCommandLineOptionWithMode("cpus", "1", SET_FLAGS_DEFAULT);
2264 }
2265 
SetDefaultFlagsForMcu()2266 void SetDefaultFlagsForMcu() {
2267   auto path = DefaultHostArtifactsPath("etc/mcu_config.json");
2268   if (!CanAccess(path, R_OK)) {
2269     return;
2270   }
2271   SetCommandLineOptionWithMode("mcu_config_path", path.c_str(), SET_FLAGS_DEFAULT);
2272 }
2273 
SetDefaultFlagsForOpenwrt(Arch target_arch)2274 void SetDefaultFlagsForOpenwrt(Arch target_arch) {
2275   if (target_arch == Arch::X86_64) {
2276     SetCommandLineOptionWithMode(
2277         "ap_kernel_image",
2278         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_kernel_x86_64")
2279             .c_str(),
2280         SET_FLAGS_DEFAULT);
2281     SetCommandLineOptionWithMode(
2282         "ap_rootfs_image",
2283         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs_x86_64")
2284             .c_str(),
2285         SET_FLAGS_DEFAULT);
2286   } else if (target_arch == Arch::Arm64) {
2287     SetCommandLineOptionWithMode(
2288         "ap_kernel_image",
2289         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_kernel_aarch64")
2290             .c_str(),
2291         SET_FLAGS_DEFAULT);
2292     SetCommandLineOptionWithMode(
2293         "ap_rootfs_image",
2294         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs_aarch64")
2295             .c_str(),
2296         SET_FLAGS_DEFAULT);
2297   }
2298 }
2299 
GetGuestConfigAndSetDefaults()2300 Result<std::vector<GuestConfig>> GetGuestConfigAndSetDefaults() {
2301   auto instance_nums =
2302       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
2303   int32_t instances_size = instance_nums.size();
2304   CF_EXPECT(ResolveInstanceFiles(), "Failed to resolve instance files");
2305 
2306   std::vector<GuestConfig> guest_configs = CF_EXPECT(ReadGuestConfig());
2307 
2308   // TODO(weihsu), b/250988697:
2309   // assume all instances are using same VM manager/app/arch,
2310   // later that multiple instances may use different VM manager/app/arch
2311 
2312   // Temporary add this checking to make sure all instances have same target_arch.
2313   // This checking should be removed later.
2314   for (int instance_index = 1; instance_index < guest_configs.size(); instance_index++) {
2315     CF_EXPECT(guest_configs[0].target_arch == guest_configs[instance_index].target_arch,
2316               "all instance target_arch should be same");
2317   }
2318   if (FLAGS_vm_manager == "") {
2319     if (IsHostCompatible(guest_configs[0].target_arch)) {
2320       FLAGS_vm_manager = ToString(VmmMode::kCrosvm);
2321     } else {
2322       FLAGS_vm_manager = ToString(VmmMode::kQemu);
2323     }
2324   }
2325 
2326   std::vector<std::string> vm_manager_vec =
2327       android::base::Split(FLAGS_vm_manager, ",");
2328 
2329   // TODO(weihsu), b/250988697:
2330   // Currently, all instances should use same vmm
2331   auto vmm = CF_EXPECT(ParseVmm(vm_manager_vec[0]));
2332 
2333   // get flag default values and store into map
2334   auto name_to_default_value = CurrentFlagsToDefaultValue();
2335 
2336   if (vmm == VmmMode::kQemu) {
2337     CF_EXPECT(SetDefaultFlagsForQemu(guest_configs, name_to_default_value));
2338   } else if (vmm == VmmMode::kCrosvm) {
2339     CF_EXPECT(SetDefaultFlagsForCrosvm(guest_configs, name_to_default_value));
2340   } else if (vmm == VmmMode::kGem5) {
2341     // TODO: Get the other architectures working
2342     if (guest_configs[0].target_arch != Arch::Arm64) {
2343       return CF_ERR("Gem5 only supports ARM64");
2344     }
2345     SetDefaultFlagsForGem5();
2346   } else {
2347     return CF_ERR("Unknown Virtual Machine Manager: " << FLAGS_vm_manager);
2348   }
2349   if (vmm != VmmMode::kGem5) {
2350     // After SetCommandLineOptionWithMode in SetDefaultFlagsForCrosvm/Qemu,
2351     // default flag values changed, need recalculate name_to_default_value
2352     name_to_default_value = CurrentFlagsToDefaultValue();
2353     std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
2354         start_webrtc));
2355     bool start_webrtc = false;
2356     for(bool value : start_webrtc_vec) {
2357       start_webrtc |= value;
2358     }
2359 
2360     auto host_operator_present =
2361         cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH);
2362     // The default for starting signaling server depends on whether or not webrtc
2363     // is to be started and the presence of the host orchestrator.
2364     SetCommandLineOptionWithMode(
2365         "start_webrtc_sig_server",
2366         start_webrtc && !host_operator_present ? "true" : "false",
2367         SET_FLAGS_DEFAULT);
2368     SetCommandLineOptionWithMode(
2369         "webrtc_sig_server_addr",
2370         host_operator_present ? HOST_OPERATOR_SOCKET_PATH : "0.0.0.0",
2371         SET_FLAGS_DEFAULT);
2372   }
2373 
2374   SetDefaultFlagsForOpenwrt(guest_configs[0].target_arch);
2375 
2376   SetDefaultFlagsForMcu();
2377 
2378   // Set the env variable to empty (in case the caller passed a value for it).
2379   unsetenv(kCuttlefishConfigEnvVarName);
2380 
2381   return guest_configs;
2382 }
2383 
GetConfigFilePath(const CuttlefishConfig & config)2384 std::string GetConfigFilePath(const CuttlefishConfig& config) {
2385   return config.AssemblyPath("cuttlefish_config.json");
2386 }
2387 
GetSeccompPolicyDir()2388 std::string GetSeccompPolicyDir() {
2389   std::string kSeccompDir =
2390       "usr/share/crosvm/" + HostArchStr() + "-linux-gnu/seccomp";
2391   return DefaultHostArtifactsPath(kSeccompDir);
2392 }
2393 
2394 } // namespace cuttlefish
2395