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