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