• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "host/commands/assemble_cvd/flags.h"
17 
18 #include <android-base/logging.h>
19 #include <android-base/parsebool.h>
20 #include <android-base/parseint.h>
21 #include <android-base/strings.h>
22 #include <gflags/gflags.h>
23 #include <json/json.h>
24 #include <json/writer.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include <algorithm>
29 #include <array>
30 #include <fstream>
31 #include <iostream>
32 #include <optional>
33 #include <regex>
34 #include <set>
35 #include <sstream>
36 #include <unordered_map>
37 
38 #include <fruit/fruit.h>
39 #include <google/protobuf/text_format.h>
40 
41 #include "launch_cvd.pb.h"
42 
43 #include "common/libs/utils/base64.h"
44 #include "common/libs/utils/contains.h"
45 #include "common/libs/utils/files.h"
46 #include "common/libs/utils/flag_parser.h"
47 #include "common/libs/utils/network.h"
48 #include "flags.h"
49 #include "flags_defaults.h"
50 #include "host/commands/assemble_cvd/alloc.h"
51 #include "host/commands/assemble_cvd/boot_config.h"
52 #include "host/commands/assemble_cvd/boot_image_utils.h"
53 #include "host/commands/assemble_cvd/disk_flags.h"
54 #include "host/commands/assemble_cvd/display_flags.h"
55 #include "host/libs/config/config_flag.h"
56 #include "host/libs/config/esp.h"
57 #include "host/libs/config/host_tools_version.h"
58 #include "host/libs/config/instance_nums.h"
59 #include "host/libs/graphics_detector/graphics_configuration.h"
60 #include "host/libs/graphics_detector/graphics_detector.h"
61 #include "host/libs/vm_manager/crosvm_manager.h"
62 #include "host/libs/vm_manager/gem5_manager.h"
63 #include "host/libs/vm_manager/qemu_manager.h"
64 #include "host/libs/vm_manager/vm_manager.h"
65 
66 using cuttlefish::DefaultHostArtifactsPath;
67 using cuttlefish::HostBinaryPath;
68 using cuttlefish::StringFromEnv;
69 using cuttlefish::vm_manager::CrosvmManager;
70 using google::FlagSettingMode::SET_FLAGS_DEFAULT;
71 using google::FlagSettingMode::SET_FLAGS_VALUE;
72 
73 #define DEFINE_vec DEFINE_string
74 #define DEFINE_proto DEFINE_string
75 #define GET_FLAG_STR_VALUE(name) GetFlagStrValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
76 #define GET_FLAG_INT_VALUE(name) GetFlagIntValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
77 #define GET_FLAG_BOOL_VALUE(name) GetFlagBoolValueForInstances(FLAGS_ ##name, instances_size, #name, name_to_default_value)
78 
79 DEFINE_proto(displays_textproto, CF_DEFAULTS_DISPLAYS_TEXTPROTO,
80               "Text Proto input for multi-vd multi-displays");
81 DEFINE_proto(displays_binproto, CF_DEFAULTS_DISPLAYS_TEXTPROTO,
82               "Binary Proto input for multi-vd multi-displays");
83 
84 DEFINE_vec(cpus, std::to_string(CF_DEFAULTS_CPUS),
85               "Virtual CPU count.");
86 DEFINE_vec(data_policy, CF_DEFAULTS_DATA_POLICY,
87               "How to handle userdata partition."
88               " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
89               "'always_create'.");
90 DEFINE_vec(blank_data_image_mb,
91               std::to_string(CF_DEFAULTS_BLANK_DATA_IMAGE_MB),
92              "The size of the blank data image to generate, MB.");
93 DEFINE_vec(gdb_port, std::to_string(CF_DEFAULTS_GDB_PORT),
94              "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The"
95              "kernel must have been built with CONFIG_RANDOMIZE_BASE "
96              "disabled.");
97 
98 // TODO(b/192495477): combine these into a single repeatable '--display' flag
99 // when assemble_cvd switches to using the new flag parsing library.
100 DEFINE_string(display0, CF_DEFAULTS_DISPLAY0, cuttlefish::kDisplayHelp);
101 DEFINE_string(display1, CF_DEFAULTS_DISPLAY1, cuttlefish::kDisplayHelp);
102 DEFINE_string(display2, CF_DEFAULTS_DISPLAY2, cuttlefish::kDisplayHelp);
103 DEFINE_string(display3, CF_DEFAULTS_DISPLAY3, cuttlefish::kDisplayHelp);
104 
105 // TODO(b/171305898): mark these as deprecated after multi-display is fully
106 // enabled.
107 DEFINE_string(x_res, "0", "Width of the screen in pixels");
108 DEFINE_string(y_res, "0", "Height of the screen in pixels");
109 DEFINE_string(dpi, "0", "Pixels per inch for the screen");
110 DEFINE_string(refresh_rate_hz, "60", "Screen refresh rate in Hertz");
111 DEFINE_vec(kernel_path, CF_DEFAULTS_KERNEL_PATH,
112               "Path to the kernel. Overrides the one from the boot image");
113 DEFINE_vec(initramfs_path, CF_DEFAULTS_INITRAMFS_PATH,
114               "Path to the initramfs");
115 DEFINE_string(extra_kernel_cmdline, CF_DEFAULTS_EXTRA_KERNEL_CMDLINE,
116               "Additional flags to put on the kernel command line");
117 DEFINE_string(extra_bootconfig_args, CF_DEFAULTS_EXTRA_BOOTCONFIG_ARGS,
118               "Space-separated list of extra bootconfig args. "
119               "Note: overwriting an existing bootconfig argument "
120               "requires ':=' instead of '='.");
121 DEFINE_vec(guest_enforce_security,
122               cuttlefish::BoolToString(CF_DEFAULTS_GUEST_ENFORCE_SECURITY),
123             "Whether to run in enforcing mode (non permissive).");
124 DEFINE_vec(memory_mb, std::to_string(CF_DEFAULTS_MEMORY_MB),
125              "Total amount of memory available for guest, MB.");
126 DEFINE_vec(serial_number, CF_DEFAULTS_SERIAL_NUMBER,
127               "Serial number to use for the device");
128 DEFINE_vec(use_random_serial, cuttlefish::BoolToString(CF_DEFAULTS_USE_RANDOM_SERIAL),
129             "Whether to use random serial for the device.");
130 DEFINE_vec(vm_manager, CF_DEFAULTS_VM_MANAGER,
131               "What virtual machine manager to use, one of {qemu_cli, crosvm}");
132 DEFINE_vec(gpu_mode, CF_DEFAULTS_GPU_MODE,
133               "What gpu configuration to use, one of {auto, drm_virgl, "
134               "gfxstream, guest_swiftshader}");
135 DEFINE_vec(hwcomposer, CF_DEFAULTS_HWCOMPOSER,
136               "What hardware composer to use, one of {auto, drm, ranchu} ");
137 DEFINE_vec(gpu_capture_binary, CF_DEFAULTS_GPU_CAPTURE_BINARY,
138               "Path to the GPU capture binary to use when capturing GPU traces"
139               "(ngfx, renderdoc, etc)");
140 DEFINE_vec(enable_gpu_udmabuf,
141            cuttlefish::BoolToString(CF_DEFAULTS_ENABLE_GPU_UDMABUF),
142            "Use the udmabuf driver for zero-copy virtio-gpu");
143 
144 DEFINE_vec(use_allocd, CF_DEFAULTS_USE_ALLOCD?"true":"false",
145             "Acquire static resources from the resource allocator daemon.");
146 DEFINE_vec(
147     enable_minimal_mode, CF_DEFAULTS_ENABLE_MINIMAL_MODE ? "true" : "false",
148     "Only enable the minimum features to boot a cuttlefish device and "
149     "support minimal UI interactions.\nNote: Currently only supports "
150     "handheld/phone targets");
151 DEFINE_vec(
152     pause_in_bootloader, CF_DEFAULTS_PAUSE_IN_BOOTLOADER?"true":"false",
153     "Stop the bootflow in u-boot. You can continue the boot by connecting "
154     "to the device console and typing in \"boot\".");
155 DEFINE_bool(enable_host_bluetooth, CF_DEFAULTS_ENABLE_HOST_BLUETOOTH,
156             "Enable the root-canal which is Bluetooth emulator in the host.");
157 DEFINE_int32(
158     rootcanal_instance_num, CF_DEFAULTS_ENABLE_ROOTCANAL_INSTANCE_NUM,
159     "If it is greater than 0, use an existing rootcanal instance which is "
160     "launched from cuttlefish instance "
161     "with rootcanal_instance_num. Else, launch a new rootcanal instance");
162 DEFINE_string(rootcanal_args, CF_DEFAULTS_ROOTCANAL_ARGS,
163               "Space-separated list of rootcanal args. ");
164 DEFINE_bool(enable_host_uwb, CF_DEFAULTS_ENABLE_HOST_UWB,
165             "Enable Pica in the host.");
166 DEFINE_int32(
167     pica_instance_num, CF_DEFAULTS_ENABLE_PICA_INSTANCE_NUM,
168     "If it is greater than 0, use an existing pica instance which is "
169     "launched from cuttlefish instance "
170     "with pica_instance_num. Else, launch a new pica instance");
171 DEFINE_bool(netsim, CF_DEFAULTS_NETSIM,
172             "[Experimental] Connect all radios to netsim.");
173 
174 DEFINE_bool(netsim_bt, CF_DEFAULTS_NETSIM_BT,
175             "[Experimental] Connect Bluetooth radio to netsim.");
176 
177 DEFINE_string(bluetooth_controller_properties_file,
178               CF_DEFAULTS_BLUETOOTH_CONTROLLER_PROPERTIES_FILE,
179               "The configuartion file path for root-canal which is a Bluetooth "
180               "emulator.");
181 DEFINE_string(
182     bluetooth_default_commands_file,
183     CF_DEFAULTS_BLUETOOTH_DEFAULT_COMMANDS_FILE,
184     "The default commands which root-canal executes when it launches.");
185 
186 /**
187  * crosvm sandbox feature requires /var/empty and seccomp directory
188  *
189  * Also see SetDefaultFlagsForCrosvm()
190  */
191 DEFINE_vec(
192     enable_sandbox, cuttlefish::BoolToString(CF_DEFAULTS_ENABLE_SANDBOX),
193     "Enable crosvm sandbox assuming /var/empty and seccomp directories exist. "
194     "--noenable-sandbox will disable crosvm sandbox. "
195     "When no option is given, sandbox is disabled if Cuttlefish is running "
196     "inside a container, or if GPU is enabled (b/152323505), "
197     "or if the empty /var/empty directory either does not exist and "
198     "cannot be created. Otherwise, sandbox is enabled on the supported "
199     "architecture when no option is given.");
200 
201 DEFINE_string(
202     seccomp_policy_dir, CF_DEFAULTS_SECCOMP_POLICY_DIR,
203     "With sandbox'ed crosvm, overrieds the security comp policy directory");
204 
205 DEFINE_vec(start_webrtc, cuttlefish::BoolToString(CF_DEFAULTS_START_WEBRTC),
206             "Whether to start the webrtc process.");
207 
208 DEFINE_vec(webrtc_assets_dir, CF_DEFAULTS_WEBRTC_ASSETS_DIR,
209               "[Experimental] Path to WebRTC webpage assets.");
210 
211 DEFINE_string(webrtc_certs_dir, CF_DEFAULTS_WEBRTC_CERTS_DIR,
212               "[Experimental] Path to WebRTC certificates directory.");
213 
214 static constexpr auto HOST_OPERATOR_SOCKET_PATH = "/run/cuttlefish/operator";
215 
216 DEFINE_bool(
217     // The actual default for this flag is set with SetCommandLineOption() in
218     // GetGuestConfigsAndSetDefaults() at the end of this file.
219     start_webrtc_sig_server, CF_DEFAULTS_START_WEBRTC_SIG_SERVER,
220     "Whether to start the webrtc signaling server. This option only applies to "
221     "the first instance, if multiple instances are launched they'll share the "
222     "same signaling server, which is owned by the first one.");
223 
224 DEFINE_string(webrtc_sig_server_addr, CF_DEFAULTS_WEBRTC_SIG_SERVER_ADDR,
225               "The address of the webrtc signaling server.");
226 
227 DEFINE_int32(
228     webrtc_sig_server_port, CF_DEFAULTS_WEBRTC_SIG_SERVER_PORT,
229     "The port of the signaling server if started outside of this launch. If "
230     "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
231     "this parameter is ignored.");
232 
233 // TODO (jemoreira): We need a much bigger range to reliably support several
234 // simultaneous connections.
235 DEFINE_vec(tcp_port_range, CF_DEFAULTS_TCP_PORT_RANGE,
236               "The minimum and maximum TCP port numbers to allocate for ICE "
237               "candidates as 'min:max'. To use any port just specify '0:0'");
238 
239 DEFINE_vec(udp_port_range, CF_DEFAULTS_UDP_PORT_RANGE,
240               "The minimum and maximum UDP port numbers to allocate for ICE "
241               "candidates as 'min:max'. To use any port just specify '0:0'");
242 
243 DEFINE_string(webrtc_sig_server_path, CF_DEFAULTS_WEBRTC_SIG_SERVER_PATH,
244               "The path section of the URL where the device should be "
245               "registered with the signaling server.");
246 
247 DEFINE_bool(
248     webrtc_sig_server_secure, CF_DEFAULTS_WEBRTC_SIG_SERVER_SECURE,
249     "Whether the WebRTC signaling server uses secure protocols (WSS vs WS).");
250 
251 DEFINE_bool(verify_sig_server_certificate,
252             CF_DEFAULTS_VERIFY_SIG_SERVER_CERTIFICATE,
253             "Whether to verify the signaling server's certificate with a "
254             "trusted signing authority (Disallow self signed certificates). "
255             "This is ignored if an insecure server is configured.");
256 
257 DEFINE_vec(
258     webrtc_device_id, CF_DEFAULTS_WEBRTC_DEVICE_ID,
259     "The for the device to register with the signaling server. Every "
260     "appearance of the substring '{num}' in the device id will be substituted "
261     "with the instance number to support multiple instances");
262 
263 DEFINE_vec(uuid, CF_DEFAULTS_UUID,
264               "UUID to use for the device. Random if not specified");
265 DEFINE_vec(daemon, CF_DEFAULTS_DAEMON?"true":"false",
266             "Run cuttlefish in background, the launcher exits on boot "
267             "completed/failed");
268 
269 DEFINE_vec(setupwizard_mode, CF_DEFAULTS_SETUPWIZARD_MODE,
270               "One of DISABLED,OPTIONAL,REQUIRED");
271 DEFINE_vec(enable_bootanimation,
272            cuttlefish::BoolToString(CF_DEFAULTS_ENABLE_BOOTANIMATION),
273            "Whether to enable the boot animation.");
274 
275 DEFINE_string(qemu_binary_dir, CF_DEFAULTS_QEMU_BINARY_DIR,
276               "Path to the directory containing the qemu binary to use");
277 DEFINE_string(crosvm_binary, CF_DEFAULTS_CROSVM_BINARY,
278               "The Crosvm binary to use");
279 DEFINE_vec(gem5_binary_dir, CF_DEFAULTS_GEM5_BINARY_DIR,
280               "Path to the gem5 build tree root");
281 DEFINE_vec(gem5_checkpoint_dir, CF_DEFAULTS_GEM5_CHECKPOINT_DIR,
282               "Path to the gem5 restore checkpoint directory");
283 DEFINE_vec(gem5_debug_file, CF_DEFAULTS_GEM5_DEBUG_FILE,
284               "The file name where gem5 saves debug prints and logs");
285 DEFINE_string(gem5_debug_flags, CF_DEFAULTS_GEM5_DEBUG_FLAGS,
286               "The debug flags gem5 uses to print debugs to file");
287 
288 DEFINE_vec(restart_subprocesses,
289               cuttlefish::BoolToString(CF_DEFAULTS_RESTART_SUBPROCESSES),
290               "Restart any crashed host process");
291 DEFINE_vec(bootloader, CF_DEFAULTS_BOOTLOADER, "Bootloader binary path");
292 DEFINE_vec(boot_slot, CF_DEFAULTS_BOOT_SLOT,
293               "Force booting into the given slot. If empty, "
294               "the slot will be chosen based on the misc partition if using a "
295               "bootloader. It will default to 'a' if empty and not using a "
296               "bootloader.");
297 DEFINE_int32(num_instances, CF_DEFAULTS_NUM_INSTANCES,
298              "Number of Android guests to launch");
299 DEFINE_string(instance_nums, CF_DEFAULTS_INSTANCE_NUMS,
300               "A comma-separated list of instance numbers "
301               "to use. Mutually exclusive with base_instance_num.");
302 DEFINE_string(report_anonymous_usage_stats,
303               CF_DEFAULTS_REPORT_ANONYMOUS_USAGE_STATS,
304               "Report anonymous usage "
305               "statistics for metrics collection and analysis.");
306 DEFINE_vec(ril_dns, CF_DEFAULTS_RIL_DNS,
307               "DNS address of mobile network (RIL)");
308 DEFINE_vec(kgdb, cuttlefish::BoolToString(CF_DEFAULTS_KGDB),
309             "Configure the virtual device for debugging the kernel "
310             "with kgdb/kdb. The kernel must have been built with "
311             "kgdb support, and serial console must be enabled.");
312 
313 DEFINE_vec(start_gnss_proxy, cuttlefish::BoolToString(CF_DEFAULTS_START_GNSS_PROXY),
314             "Whether to start the gnss proxy.");
315 
316 DEFINE_vec(gnss_file_path, CF_DEFAULTS_GNSS_FILE_PATH,
317               "Local gnss raw measurement file path for the gnss proxy");
318 
319 DEFINE_vec(fixed_location_file_path, CF_DEFAULTS_FIXED_LOCATION_FILE_PATH,
320               "Local fixed location file path for the gnss proxy");
321 
322 // by default, this modem-simulator is disabled
323 DEFINE_vec(enable_modem_simulator,
324               CF_DEFAULTS_ENABLE_MODEM_SIMULATOR ? "true" : "false",
325               "Enable the modem simulator to process RILD AT commands");
326 // modem_simulator_sim_type=2 for test CtsCarrierApiTestCases
327 DEFINE_vec(modem_simulator_sim_type,
328               std::to_string(CF_DEFAULTS_MODEM_SIMULATOR_SIM_TYPE),
329               "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
330 
331 DEFINE_vec(console, cuttlefish::BoolToString(CF_DEFAULTS_CONSOLE),
332               "Enable the serial console");
333 
334 DEFINE_vec(enable_kernel_log,
335            cuttlefish::BoolToString(CF_DEFAULTS_ENABLE_KERNEL_LOG),
336             "Enable kernel console/dmesg logging");
337 
338 DEFINE_vec(vhost_net, cuttlefish::BoolToString(CF_DEFAULTS_VHOST_NET),
339             "Enable vhost acceleration of networking");
340 
341 DEFINE_string(
342     vhost_user_mac80211_hwsim, CF_DEFAULTS_VHOST_USER_MAC80211_HWSIM,
343     "Unix socket path for vhost-user of mac80211_hwsim, typically served by "
344     "wmediumd. You can set this when using an external wmediumd instance.");
345 DEFINE_string(wmediumd_config, CF_DEFAULTS_WMEDIUMD_CONFIG,
346               "Path to the wmediumd config file. When missing, the default "
347               "configuration is used which adds MAC addresses for up to 16 "
348               "cuttlefish instances including AP.");
349 
350 DEFINE_string(ap_rootfs_image, CF_DEFAULTS_AP_ROOTFS_IMAGE,
351               "rootfs image for AP instance");
352 DEFINE_string(ap_kernel_image, CF_DEFAULTS_AP_KERNEL_IMAGE,
353               "kernel image for AP instance");
354 
355 DEFINE_vec(record_screen, cuttlefish::BoolToString(CF_DEFAULTS_RECORD_SCREEN),
356            "Enable screen recording. "
357            "Requires --start_webrtc");
358 
359 DEFINE_vec(smt, cuttlefish::BoolToString(CF_DEFAULTS_SMT),
360            "Enable simultaneous multithreading (SMT/HT)");
361 
362 DEFINE_vec(
363     vsock_guest_cid, std::to_string(CF_DEFAULTS_VSOCK_GUEST_CID),
364     "vsock_guest_cid is used to determine the guest vsock cid as well as all "
365     "the ports"
366     "of all vsock servers such as tombstone or modem simulator(s)."
367     "The vsock ports and guest vsock cid are a function of vsock_guest_cid and "
368     "instance number."
369     "An instance number of i th instance is determined by --num_instances=N "
370     "and --base_instance_num=B"
371     "The instance number of i th instance is B + i where i in [0, N-1] and B "
372     ">= 1."
373     "See --num_instances, and --base_instance_num for more information"
374     "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. "
375     "Otherwise,"
376     "the guest vsock cid is 2 + instance number, which is 2 + (B + i)."
377     "If --vsock_guest_cid is not given, each vsock server port number for i th "
378     "instance is"
379     "base + instance number - 1. vsock_guest_cid is by default B + i + 2."
380     "Thus, by default, each port is base + vsock_guest_cid - 3."
381     "The same formula holds when --vsock_guest_cid=C is given, for algorithm's "
382     "sake."
383     "Each vsock server port number is base + C - 3.");
384 
385 DEFINE_string(secure_hals, CF_DEFAULTS_SECURE_HALS,
386               "Which HALs to use enable host security features for. Supports "
387               "keymint and gatekeeper at the moment.");
388 
389 DEFINE_vec(use_sdcard, CF_DEFAULTS_USE_SDCARD?"true":"false",
390             "Create blank SD-Card image and expose to guest");
391 
392 DEFINE_vec(protected_vm, cuttlefish::BoolToString(CF_DEFAULTS_PROTECTED_VM),
393             "Boot in Protected VM mode");
394 
395 DEFINE_vec(mte, cuttlefish::BoolToString(CF_DEFAULTS_MTE), "Enable MTE");
396 
397 DEFINE_vec(enable_audio, cuttlefish::BoolToString(CF_DEFAULTS_ENABLE_AUDIO),
398             "Whether to play or capture audio");
399 
400 DEFINE_vec(camera_server_port, std::to_string(CF_DEFAULTS_CAMERA_SERVER_PORT),
401               "camera vsock port");
402 
403 DEFINE_vec(userdata_format, CF_DEFAULTS_USERDATA_FORMAT,
404               "The userdata filesystem format");
405 
406 DEFINE_bool(use_overlay, CF_DEFAULTS_USE_OVERLAY,
407             "Capture disk writes an overlay. This is a "
408             "prerequisite for powerwash_cvd or multiple instances.");
409 
410 DEFINE_vec(modem_simulator_count,
411               std::to_string(CF_DEFAULTS_MODEM_SIMULATOR_COUNT),
412               "Modem simulator count corresponding to maximum sim number");
413 
414 DECLARE_string(assembly_dir);
415 DECLARE_string(boot_image);
416 DECLARE_string(system_image_dir);
417 
418 namespace cuttlefish {
419 using vm_manager::QemuManager;
420 using vm_manager::Gem5Manager;
421 using vm_manager::GetVmManager;
422 
423 namespace {
424 
ParsePortRange(const std::string & flag)425 std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
426   static const std::regex rgx("[0-9]+:[0-9]+");
427   CHECK(std::regex_match(flag, rgx))
428       << "Port range flag has invalid value: " << flag;
429   std::pair<uint16_t, uint16_t> port_range;
430   std::stringstream ss(flag);
431   char c;
432   ss >> port_range.first;
433   ss.read(&c, 1);
434   ss >> port_range.second;
435   return port_range;
436 }
437 
StrForInstance(const std::string & prefix,int num)438 std::string StrForInstance(const std::string& prefix, int num) {
439   std::ostringstream stream;
440   stream << prefix << std::setfill('0') << std::setw(2) << num;
441   return stream.str();
442 }
443 
444 #ifdef __ANDROID__
ReadGuestConfig()445 Result<std::vector<GuestConfig>> ReadGuestConfig() {
446   std::vector<GuestConfig> rets;
447   auto instance_nums =
448       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
449   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
450     // QEMU isn't on Android, so always follow host arch
451     GuestConfig ret{};
452     ret.target_arch = HostArch();
453     ret.bootconfig_supported = true;
454     ret.android_version_number = "0.0.0";
455     rets.push_back(ret);
456   }
457   return rets;
458 }
459 #else
ReadGuestConfig()460 Result<std::vector<GuestConfig>> ReadGuestConfig() {
461   std::vector<GuestConfig> guest_configs;
462   std::vector<std::string> boot_image =
463       android::base::Split(FLAGS_boot_image, ",");
464   std::vector<std::string> kernel_path =
465       android::base::Split(FLAGS_kernel_path, ",");
466   std::string kernel_image_path = "";
467   std::string cur_boot_image;
468   std::string cur_kernel_path;
469 
470   std::string current_path = StringFromEnv("PATH", "");
471   std::string bin_folder = DefaultHostArtifactsPath("bin");
472   std::string new_path = "PATH=";
473   new_path += current_path;
474   new_path += ":";
475   new_path += bin_folder;
476   auto instance_nums =
477       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
478   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
479     // extract-ikconfig can be called directly on the boot image since it looks
480     // for the ikconfig header in the image before extracting the config list.
481     // This code is liable to break if the boot image ever includes the
482     // ikconfig header outside the kernel.
483     cur_kernel_path = "";
484     if (instance_index < kernel_path.size()) {
485       cur_kernel_path = kernel_path[instance_index];
486     }
487 
488     cur_boot_image = "";
489     if (instance_index < boot_image.size()) {
490       cur_boot_image = boot_image[instance_index];
491     }
492 
493     if (cur_kernel_path.size() > 0) {
494       kernel_image_path = cur_kernel_path;
495     } else if (cur_boot_image.size() > 0) {
496       kernel_image_path = cur_boot_image;
497     }
498 
499     Command ikconfig_cmd(HostBinaryPath("extract-ikconfig"));
500     ikconfig_cmd.AddParameter(kernel_image_path);
501     ikconfig_cmd.SetEnvironment({new_path});
502 
503     std::string ikconfig_path =
504         StringFromEnv("TEMP", "/tmp") + "/ikconfig.XXXXXX";
505     auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path);
506     CF_EXPECT(ikconfig_fd->IsOpen(),
507               "Unable to create ikconfig file: " << ikconfig_fd->StrError());
508     ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, ikconfig_fd);
509 
510     auto ikconfig_proc = ikconfig_cmd.Start();
511     CF_EXPECT(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0,
512               "Failed to extract ikconfig from " << kernel_image_path);
513 
514     std::string config = ReadFile(ikconfig_path);
515 
516     GuestConfig guest_config;
517     if (config.find("\nCONFIG_ARM=y") != std::string::npos) {
518       guest_config.target_arch = Arch::Arm;
519     } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) {
520       guest_config.target_arch = Arch::Arm64;
521     } else if (config.find("\nCONFIG_ARCH_RV64I=y") != std::string::npos) {
522       guest_config.target_arch = Arch::RiscV64;
523     } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) {
524       guest_config.target_arch = Arch::X86_64;
525     } else if (config.find("\nCONFIG_X86=y") != std::string::npos) {
526       guest_config.target_arch = Arch::X86;
527     } else {
528       return CF_ERR("Unknown target architecture");
529     }
530     guest_config.bootconfig_supported =
531         config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos;
532     // Once all Cuttlefish kernel versions are at least 5.15, this code can be
533     // removed. CONFIG_CRYPTO_HCTR2=y will always be set.
534     guest_config.hctr2_supported =
535         config.find("\nCONFIG_CRYPTO_HCTR2=y") != std::string::npos;
536 
537     unlink(ikconfig_path.c_str());
538     guest_config.android_version_number =
539         CF_EXPECT(ReadAndroidVersionFromBootImage(cur_boot_image),
540                   "Failed to read guest's android version");
541     ;
542     guest_configs.push_back(guest_config);
543   }
544   return guest_configs;
545 }
546 
547 #endif  // #ifdef __ANDROID__
548 
549 template <typename ProtoType>
ParseTextProtoFlagHelper(const std::string & flag_value,const std::string & flag_name)550 Result<ProtoType> ParseTextProtoFlagHelper(const std::string& flag_value,
551                                        const std::string& flag_name) {
552   ProtoType proto_result;
553   google::protobuf::TextFormat::Parser p;
554   CF_EXPECT(p.ParseFromString(flag_value, &proto_result),
555             "Failed to parse: " << flag_name << ", value: " << flag_value);
556   return proto_result;
557 }
558 
559 template <typename ProtoType>
ParseBinProtoFlagHelper(const std::string & flag_value,const std::string & flag_name)560 Result<ProtoType> ParseBinProtoFlagHelper(const std::string& flag_value,
561                                        const std::string& flag_name) {
562   ProtoType proto_result;
563   std::vector<uint8_t> output;
564   CF_EXPECT(DecodeBase64(flag_value, &output));
565   std::string serialized = std::string(output.begin(), output.end());
566 
567   CF_EXPECT(proto_result.ParseFromString(serialized),
568             "Failed to parse binary proto, flag: "<< flag_name << ", value: " << flag_value);
569   return proto_result;
570 }
571 
572 Result<std::vector<std::vector<CuttlefishConfig::DisplayConfig>>>
ParseDisplaysProto()573     ParseDisplaysProto() {
574   auto proto_result = FLAGS_displays_textproto.empty() ? \
575   ParseBinProtoFlagHelper<InstancesDisplays>(FLAGS_displays_binproto, "displays_binproto") : \
576   ParseTextProtoFlagHelper<InstancesDisplays>(FLAGS_displays_textproto, "displays_textproto");
577 
578   std::vector<std::vector<CuttlefishConfig::DisplayConfig>> result;
579   for (int i=0; i<proto_result->instances_size(); i++) {
580     std::vector<CuttlefishConfig::DisplayConfig> display_configs;
581     const InstanceDisplays& launch_cvd_instance = proto_result->instances(i);
582     for (int display_num=0; display_num<launch_cvd_instance.displays_size(); display_num++) {
583       const InstanceDisplay& display = launch_cvd_instance.displays(display_num);
584 
585       // use same code logic from ParseDisplayConfig
586       int display_dpi = CF_DEFAULTS_DISPLAY_DPI;
587       if (display.dpi() != 0) {
588         display_dpi = display.dpi();
589       }
590 
591       int display_refresh_rate_hz = CF_DEFAULTS_DISPLAY_REFRESH_RATE;
592       if (display.refresh_rate_hertz() != 0) {
593         display_refresh_rate_hz = display.refresh_rate_hertz();
594       }
595 
596       display_configs.push_back(CuttlefishConfig::DisplayConfig{
597         .width = display.width(),
598         .height = display.height(),
599         .dpi = display_dpi,
600         .refresh_rate_hz = display_refresh_rate_hz,
601         });
602     }
603     result.push_back(display_configs);
604   }
605   return result;
606 }
607 
ParseBool(const std::string & flag_str,const std::string & flag_name)608 Result<bool> ParseBool(const std::string& flag_str,
609                         const std::string& flag_name) {
610   auto result = android::base::ParseBool(flag_str);
611   CF_EXPECT(result != android::base::ParseBoolResult::kError,
612             "Failed to parse value \"" << flag_str
613             << "\" for " << flag_name);
614   if (result == android::base::ParseBoolResult::kTrue) {
615     return true;
616   }
617   return false;
618 }
619 
CreateNumToWebrtcDeviceIdMap(const CuttlefishConfig & tmp_config_obj,const std::vector<std::int32_t> & instance_nums,const std::string & webrtc_device_id_flag)620 Result<std::unordered_map<int, std::string>> CreateNumToWebrtcDeviceIdMap(
621     const CuttlefishConfig& tmp_config_obj,
622     const std::vector<std::int32_t>& instance_nums,
623     const std::string& webrtc_device_id_flag) {
624   std::unordered_map<int, std::string> output_map;
625   if (webrtc_device_id_flag.empty()) {
626     for (const auto num : instance_nums) {
627       const auto const_instance = tmp_config_obj.ForInstance(num);
628       output_map[num] = const_instance.instance_name();
629     }
630     return output_map;
631   }
632   auto tokens = android::base::Tokenize(webrtc_device_id_flag, ",");
633   CF_EXPECT(tokens.size() == 1 || tokens.size() == instance_nums.size(),
634             "--webrtc_device_ids provided " << tokens.size()
635                                             << " tokens"
636                                                " while 1 or "
637                                             << instance_nums.size()
638                                             << " is expected.");
639   CF_EXPECT(!tokens.empty(), "--webrtc_device_ids is ill-formatted");
640 
641   std::vector<std::string> device_ids;
642   if (tokens.size() != instance_nums.size()) {
643     /* this is only possible when tokens.size() == 1
644      * and instance_nums.size() > 1. The token must include {num}
645      * so that the token pattern can be expanded to multiple instances.
646      */
647     auto device_id = tokens.front();
648     CF_EXPECT(device_id.find("{num}") != std::string::npos,
649               "If one webrtc_device_ids is given for multiple instances, "
650                   << " {num} should be included in webrtc_device_id.");
651     device_ids = std::move(
652         std::vector<std::string>(instance_nums.size(), tokens.front()));
653   }
654 
655   if (tokens.size() == instance_nums.size()) {
656     // doesn't have to include {num}
657     device_ids = std::move(tokens);
658   }
659 
660   auto itr = device_ids.begin();
661   for (const auto num : instance_nums) {
662     std::string_view device_id_view(itr->data(), itr->size());
663     output_map[num] = android::base::StringReplace(device_id_view, "{num}",
664                                                    std::to_string(num), true);
665     ++itr;
666   }
667   return output_map;
668 }
669 
670 /**
671  * Returns a mapping between flag name and "gflags default_value" as strings for flags
672  * defined in the binary.
673  */
CurrentFlagsToDefaultValue()674 std::map<std::string, std::string> CurrentFlagsToDefaultValue() {
675   std::map<std::string, std::string> name_to_default_value;
676   std::vector<gflags::CommandLineFlagInfo> self_flags;
677   gflags::GetAllFlags(&self_flags);
678   for (auto& flag : self_flags) {
679     name_to_default_value[flag.name] = flag.default_value;
680   }
681   return name_to_default_value;
682 }
683 
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)684 Result<std::vector<bool>> GetFlagBoolValueForInstances(
685     const std::string& flag_values, int32_t instances_size, const std::string& flag_name,
686     std::map<std::string, std::string>& name_to_default_value) {
687   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
688   std::vector<bool> value_vec(instances_size);
689 
690   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
691   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
692 
693   for (int instance_index=0; instance_index<instances_size; instance_index++) {
694     if (instance_index >= flag_vec.size()) {
695       value_vec[instance_index] = CF_EXPECT(ParseBool(flag_vec[0], flag_name));
696     } else {
697       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
698         std::string default_value = default_value_vec[0];
699         if (instance_index < default_value_vec.size()) {
700           default_value = default_value_vec[instance_index];
701         }
702         value_vec[instance_index] = CF_EXPECT(ParseBool(default_value, flag_name));
703       } else {
704         value_vec[instance_index] = CF_EXPECT(ParseBool(flag_vec[instance_index], flag_name));
705       }
706     }
707   }
708   return value_vec;
709 }
710 
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)711 Result<std::vector<int>> GetFlagIntValueForInstances(
712     const std::string& flag_values, int32_t instances_size, const std::string& flag_name,
713     std::map<std::string, std::string>& name_to_default_value) {
714   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
715   std::vector<int> value_vec(instances_size);
716 
717   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
718   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
719 
720   for (int instance_index=0; instance_index<instances_size; instance_index++) {
721     if (instance_index >= flag_vec.size()) {
722       CF_EXPECT(android::base::ParseInt(flag_vec[0].c_str(), &value_vec[instance_index]),
723       "Failed to parse value \"" << flag_vec[0] << "\" for " << flag_name);
724     } else {
725       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
726         std::string default_value = default_value_vec[0];
727         if (instance_index < default_value_vec.size()) {
728           default_value = default_value_vec[instance_index];
729         }
730         CF_EXPECT(android::base::ParseInt(default_value,
731         &value_vec[instance_index]),
732         "Failed to parse value \"" << default_value << "\" for " << flag_name);
733       } else {
734         CF_EXPECT(android::base::ParseInt(flag_vec[instance_index].c_str(),
735         &value_vec[instance_index]),
736         "Failed to parse value \"" << flag_vec[instance_index] << "\" for " << flag_name);
737       }
738     }
739   }
740   return value_vec;
741 }
742 
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)743 Result<std::vector<std::string>> GetFlagStrValueForInstances(
744     const std::string& flag_values, int32_t instances_size,
745     const std::string& flag_name, std::map<std::string, std::string>& name_to_default_value) {
746   std::vector<std::string> flag_vec = android::base::Split(flag_values, ",");
747   std::vector<std::string> value_vec(instances_size);
748 
749   CF_EXPECT(name_to_default_value.find(flag_name) != name_to_default_value.end());
750   std::vector<std::string> default_value_vec =  android::base::Split(name_to_default_value[flag_name], ",");
751 
752   for (int instance_index=0; instance_index<instances_size; instance_index++) {
753     if (instance_index >= flag_vec.size()) {
754       value_vec[instance_index] = flag_vec[0];
755     } else {
756       if (flag_vec[instance_index] == "unset" || flag_vec[instance_index] == "\"unset\"") {
757         std::string default_value = default_value_vec[0];
758         if (instance_index < default_value_vec.size()) {
759           default_value = default_value_vec[instance_index];
760         }
761         value_vec[instance_index] = default_value;
762       } else {
763         value_vec[instance_index] = flag_vec[instance_index];
764       }
765     }
766   }
767   return value_vec;
768 }
769 
770 } // namespace
771 
InitializeCuttlefishConfiguration(const std::string & root_dir,const std::vector<GuestConfig> & guest_configs,fruit::Injector<> & injector,const FetcherConfig & fetcher_config)772 Result<CuttlefishConfig> InitializeCuttlefishConfiguration(
773     const std::string& root_dir,
774     const std::vector<GuestConfig>& guest_configs,
775     fruit::Injector<>& injector, const FetcherConfig& fetcher_config) {
776   CuttlefishConfig tmp_config_obj;
777 
778   for (const auto& fragment : injector.getMultibindings<ConfigFragment>()) {
779     CHECK(tmp_config_obj.SaveFragment(*fragment))
780         << "Failed to save fragment " << fragment->Name();
781   }
782 
783   tmp_config_obj.set_root_dir(root_dir);
784 
785   // TODO(weihsu), b/250988697:
786   // FLAGS_vm_manager used too early, have to handle this vectorized string early
787   // Currently, all instances should use same vmm, added checking here
788   std::vector<std::string> vm_manager_vec =
789       android::base::Split(FLAGS_vm_manager, ",");
790   for (int i=1; i<vm_manager_vec.size(); i++) {
791     CF_EXPECT(
792         vm_manager_vec[0] == vm_manager_vec[i],
793         "All instances should have same vm_manager, " << FLAGS_vm_manager);
794   }
795 
796   // TODO(weihsu), b/250988697: moved bootconfig_supported and hctr2_supported
797   // into each instance, but target_arch is still in todo
798   // target_arch should be in instance later
799   auto vmm = GetVmManager(vm_manager_vec[0], guest_configs[0].target_arch);
800   if (!vmm) {
801     LOG(FATAL) << "Invalid vm_manager: " << vm_manager_vec[0];
802   }
803   tmp_config_obj.set_vm_manager(vm_manager_vec[0]);
804 
805   const GraphicsAvailability graphics_availability =
806     GetGraphicsAvailabilityWithSubprocessCheck();
807 
808   LOG(DEBUG) << graphics_availability;
809 
810   auto secure_hals = android::base::Split(FLAGS_secure_hals, ",");
811   tmp_config_obj.set_secure_hals(
812       std::set<std::string>(secure_hals.begin(), secure_hals.end()));
813 
814   tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
815   tmp_config_obj.set_extra_bootconfig_args(FLAGS_extra_bootconfig_args);
816 
817   tmp_config_obj.set_host_tools_version(HostToolsCrc());
818 
819   tmp_config_obj.set_gem5_debug_flags(FLAGS_gem5_debug_flags);
820 
821   // streaming, webrtc setup
822   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
823   tmp_config_obj.set_sig_server_secure(FLAGS_webrtc_sig_server_secure);
824   // Note: This will be overridden if the sig server is started by us
825   tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
826   tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
827   tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
828   tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
829 
830   tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
831 
832 #ifdef ENFORCE_MAC80211_HWSIM
833   tmp_config_obj.set_virtio_mac80211_hwsim(true);
834 #else
835   tmp_config_obj.set_virtio_mac80211_hwsim(false);
836 #endif
837 
838   tmp_config_obj.set_vhost_user_mac80211_hwsim(FLAGS_vhost_user_mac80211_hwsim);
839 
840   if ((FLAGS_ap_rootfs_image.empty()) != (FLAGS_ap_kernel_image.empty())) {
841     LOG(FATAL) << "Either both ap_rootfs_image and ap_kernel_image should be "
842         "set or neither should be set.";
843   }
844   // If user input multiple values, we only take the 1st value and shared with
845   // all instances
846   std::string ap_rootfs_image = "";
847   if (!FLAGS_ap_rootfs_image.empty()) {
848     ap_rootfs_image = android::base::Split(FLAGS_ap_rootfs_image, ",")[0];
849   }
850 
851   tmp_config_obj.set_ap_rootfs_image(ap_rootfs_image);
852   tmp_config_obj.set_ap_kernel_image(FLAGS_ap_kernel_image);
853 
854   tmp_config_obj.set_wmediumd_config(FLAGS_wmediumd_config);
855 
856   // netsim flags allow all radios or selecting a specific radio
857   tmp_config_obj.set_rootcanal_default_commands_file(
858       FLAGS_bluetooth_default_commands_file);
859   tmp_config_obj.set_rootcanal_config_file(
860       FLAGS_bluetooth_controller_properties_file);
861 
862   bool is_any_netsim = FLAGS_netsim || FLAGS_netsim_bt;
863   bool is_bt_netsim = FLAGS_netsim || FLAGS_netsim_bt;
864 
865   // crosvm should create fifos for Bluetooth
866   tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth || is_bt_netsim);
867 
868   // rootcanal and bt_connector should handle Bluetooth (instead of netsim)
869   tmp_config_obj.set_enable_host_bluetooth_connector(FLAGS_enable_host_bluetooth && !is_bt_netsim);
870 
871   // These flags inform NetsimServer::ResultSetup which radios it owns.
872   if (is_bt_netsim) {
873     tmp_config_obj.netsim_radio_enable(CuttlefishConfig::NetsimRadio::Bluetooth);
874   }
875   // end of vectorize ap_rootfs_image, ap_kernel_image, wmediumd_config
876 
877   auto instance_nums =
878       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
879 
880   // get flag default values and store into map
881   auto name_to_default_value = CurrentFlagsToDefaultValue();
882   // old flags but vectorized for multi-device instances
883   int32_t instances_size = instance_nums.size();
884   std::vector<std::string> gnss_file_paths =
885       CF_EXPECT(GET_FLAG_STR_VALUE(gnss_file_path));
886   std::vector<std::string> fixed_location_file_paths =
887       CF_EXPECT(GET_FLAG_STR_VALUE(fixed_location_file_path));
888   std::vector<int> x_res_vec = CF_EXPECT(GET_FLAG_INT_VALUE(x_res));
889   std::vector<int> y_res_vec = CF_EXPECT(GET_FLAG_INT_VALUE(y_res));
890   std::vector<int> dpi_vec = CF_EXPECT(GET_FLAG_INT_VALUE(dpi));
891   std::vector<int> refresh_rate_hz_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
892       refresh_rate_hz));
893   std::vector<int> memory_mb_vec = CF_EXPECT(GET_FLAG_INT_VALUE(memory_mb));
894   std::vector<int> camera_server_port_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
895       camera_server_port));
896   std::vector<int> vsock_guest_cid_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
897       vsock_guest_cid));
898   std::vector<int> cpus_vec = CF_EXPECT(GET_FLAG_INT_VALUE(cpus));
899   std::vector<int> blank_data_image_mb_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
900       blank_data_image_mb));
901   std::vector<int> gdb_port_vec = CF_EXPECT(GET_FLAG_INT_VALUE(gdb_port));
902   std::vector<std::string> setupwizard_mode_vec =
903       CF_EXPECT(GET_FLAG_STR_VALUE(setupwizard_mode));
904   std::vector<std::string> userdata_format_vec =
905       CF_EXPECT(GET_FLAG_STR_VALUE(userdata_format));
906   std::vector<bool> guest_enforce_security_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
907       guest_enforce_security));
908   std::vector<bool> use_random_serial_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
909       use_random_serial));
910   std::vector<bool> use_allocd_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_allocd));
911   std::vector<bool> use_sdcard_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_sdcard));
912   std::vector<bool> pause_in_bootloader_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
913       pause_in_bootloader));
914   std::vector<bool> daemon_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(daemon));
915   std::vector<bool> enable_minimal_mode_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
916       enable_minimal_mode));
917   std::vector<bool> enable_modem_simulator_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
918       enable_modem_simulator));
919   std::vector<int> modem_simulator_count_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
920       modem_simulator_count));
921   std::vector<int> modem_simulator_sim_type_vec = CF_EXPECT(GET_FLAG_INT_VALUE(
922       modem_simulator_sim_type));
923   std::vector<bool> console_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(console));
924   std::vector<bool> enable_audio_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_audio));
925   std::vector<bool> start_gnss_proxy_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
926       start_gnss_proxy));
927   std::vector<bool> enable_bootanimation_vec =
928       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_bootanimation));
929   std::vector<bool> record_screen_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
930       record_screen));
931   std::vector<std::string> gem5_debug_file_vec =
932       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_debug_file));
933   std::vector<bool> protected_vm_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
934       protected_vm));
935   std::vector<bool> mte_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(mte));
936   std::vector<bool> enable_kernel_log_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
937       enable_kernel_log));
938   std::vector<bool> kgdb_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(kgdb));
939   std::vector<std::string> boot_slot_vec =
940       CF_EXPECT(GET_FLAG_STR_VALUE(boot_slot));
941   std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
942       start_webrtc));
943   std::vector<std::string> webrtc_assets_dir_vec =
944       CF_EXPECT(GET_FLAG_STR_VALUE(webrtc_assets_dir));
945   std::vector<std::string> tcp_port_range_vec =
946       CF_EXPECT(GET_FLAG_STR_VALUE(tcp_port_range));
947   std::vector<std::string> udp_port_range_vec =
948       CF_EXPECT(GET_FLAG_STR_VALUE(udp_port_range));
949   std::vector<bool> vhost_net_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
950       vhost_net));
951   std::vector<std::string> ril_dns_vec =
952       CF_EXPECT(GET_FLAG_STR_VALUE(ril_dns));
953 
954   // At this time, FLAGS_enable_sandbox comes from SetDefaultFlagsForCrosvm
955   std::vector<bool> enable_sandbox_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
956       enable_sandbox));
957 
958   std::vector<std::string> gpu_mode_vec =
959       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_mode));
960   std::vector<std::string> gpu_capture_binary_vec =
961       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_capture_binary));
962   std::vector<bool> restart_subprocesses_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
963       restart_subprocesses));
964   std::vector<std::string> hwcomposer_vec =
965       CF_EXPECT(GET_FLAG_STR_VALUE(hwcomposer));
966   std::vector<bool> enable_gpu_udmabuf_vec =
967       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_gpu_udmabuf));
968   std::vector<bool> smt_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(smt));
969   std::vector<std::string> crosvm_binary_vec =
970       CF_EXPECT(GET_FLAG_STR_VALUE(crosvm_binary));
971   std::vector<std::string> seccomp_policy_dir_vec =
972       CF_EXPECT(GET_FLAG_STR_VALUE(seccomp_policy_dir));
973   std::vector<std::string> qemu_binary_dir_vec =
974       CF_EXPECT(GET_FLAG_STR_VALUE(qemu_binary_dir));
975 
976   // new instance specific flags (moved from common flags)
977   std::vector<std::string> gem5_binary_dir_vec =
978       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_binary_dir));
979   std::vector<std::string> gem5_checkpoint_dir_vec =
980       CF_EXPECT(GET_FLAG_STR_VALUE(gem5_checkpoint_dir));
981   std::vector<std::string> data_policy_vec =
982       CF_EXPECT(GET_FLAG_STR_VALUE(data_policy));
983 
984   // multi-dv multi-display proto input
985   std::vector<std::vector<CuttlefishConfig::DisplayConfig>> instances_display_configs;
986   if (!FLAGS_displays_textproto.empty() || !FLAGS_displays_binproto.empty()) {
987     instances_display_configs = CF_EXPECT(ParseDisplaysProto());
988   }
989 
990   std::string default_enable_sandbox = "";
991   std::string comma_str = "";
992 
993   CHECK(FLAGS_use_overlay || instance_nums.size() == 1)
994       << "`--use_overlay=false` is incompatible with multiple instances";
995   CHECK(instance_nums.size() > 0) << "Require at least one instance.";
996   auto rootcanal_instance_num = *instance_nums.begin() - 1;
997   if (FLAGS_rootcanal_instance_num > 0) {
998     rootcanal_instance_num = FLAGS_rootcanal_instance_num - 1;
999   }
1000   tmp_config_obj.set_rootcanal_args(FLAGS_rootcanal_args);
1001   tmp_config_obj.set_rootcanal_hci_port(7300 + rootcanal_instance_num);
1002   tmp_config_obj.set_rootcanal_link_port(7400 + rootcanal_instance_num);
1003   tmp_config_obj.set_rootcanal_test_port(7500 + rootcanal_instance_num);
1004   tmp_config_obj.set_rootcanal_link_ble_port(7600 + rootcanal_instance_num);
1005   LOG(DEBUG) << "rootcanal_instance_num: " << rootcanal_instance_num;
1006   LOG(DEBUG) << "launch rootcanal: " << (FLAGS_rootcanal_instance_num <= 0);
1007 
1008   // crosvm should create fifos for UWB
1009   auto pica_instance_num = *instance_nums.begin() - 1;
1010   if (FLAGS_pica_instance_num > 0) {
1011     pica_instance_num = FLAGS_pica_instance_num - 1;
1012   }
1013   tmp_config_obj.set_enable_host_uwb(FLAGS_enable_host_uwb);
1014   tmp_config_obj.set_enable_host_uwb_connector(FLAGS_enable_host_uwb);
1015   tmp_config_obj.set_pica_uci_port(7000 + pica_instance_num);
1016   LOG(DEBUG) << "pica_instance_num: " << pica_instance_num;
1017   LOG(DEBUG) << "launch pica: " << (FLAGS_pica_instance_num <= 0);
1018 
1019   bool is_first_instance = true;
1020   int instance_index = 0;
1021   auto num_to_webrtc_device_id_flag_map =
1022       CF_EXPECT(CreateNumToWebrtcDeviceIdMap(tmp_config_obj, instance_nums,
1023                                              FLAGS_webrtc_device_id));
1024   for (const auto& num : instance_nums) {
1025     IfaceConfig iface_config;
1026     if (use_allocd_vec[instance_index]) {
1027       auto iface_opt = AllocateNetworkInterfaces();
1028       if (!iface_opt.has_value()) {
1029         LOG(FATAL) << "Failed to acquire network interfaces";
1030       }
1031       iface_config = iface_opt.value();
1032     } else {
1033       iface_config = DefaultNetworkInterfaces(num);
1034     }
1035 
1036 
1037     auto instance = tmp_config_obj.ForInstance(num);
1038     auto const_instance =
1039         const_cast<const CuttlefishConfig&>(tmp_config_obj).ForInstance(num);
1040 
1041     instance.set_bootconfig_supported(guest_configs[instance_index].bootconfig_supported);
1042     instance.set_filename_encryption_mode(
1043       guest_configs[instance_index].hctr2_supported ? "hctr2" : "cts");
1044     instance.set_use_allocd(use_allocd_vec[instance_index]);
1045     instance.set_enable_audio(enable_audio_vec[instance_index]);
1046     instance.set_enable_gnss_grpc_proxy(start_gnss_proxy_vec[instance_index]);
1047     instance.set_enable_bootanimation(enable_bootanimation_vec[instance_index]);
1048     instance.set_record_screen(record_screen_vec[instance_index]);
1049     instance.set_gem5_debug_file(gem5_debug_file_vec[instance_index]);
1050     instance.set_protected_vm(protected_vm_vec[instance_index]);
1051     instance.set_mte(mte_vec[instance_index]);
1052     instance.set_enable_kernel_log(enable_kernel_log_vec[instance_index]);
1053     if (!boot_slot_vec[instance_index].empty()) {
1054       instance.set_boot_slot(boot_slot_vec[instance_index]);
1055     }
1056 
1057     instance.set_crosvm_binary(crosvm_binary_vec[instance_index]);
1058     instance.set_seccomp_policy_dir(seccomp_policy_dir_vec[instance_index]);
1059     instance.set_qemu_binary_dir(qemu_binary_dir_vec[instance_index]);
1060 
1061     // wifi, bluetooth, connectivity setup
1062     instance.set_ril_dns(ril_dns_vec[instance_index]);
1063 
1064     instance.set_vhost_net(vhost_net_vec[instance_index]);
1065     // end of wifi, bluetooth, connectivity setup
1066 
1067     if (use_random_serial_vec[instance_index]) {
1068       instance.set_serial_number(
1069           RandomSerialNumber("CFCVD" + std::to_string(num)));
1070     } else {
1071       instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
1072     }
1073 
1074     instance.set_grpc_socket_path(const_instance.PerInstanceGrpcSocketPath(""));
1075 
1076     // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc
1077     const auto vsock_guest_cid = vsock_guest_cid_vec[instance_index] + num - GetInstance();
1078     instance.set_vsock_guest_cid(vsock_guest_cid);
1079     auto calc_vsock_port = [vsock_guest_cid](const int base_port) {
1080       // a base (vsock) port is like 9600 for modem_simulator, etc
1081       return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid);
1082     };
1083     instance.set_session_id(iface_config.mobile_tap.session_id);
1084 
1085     instance.set_cpus(cpus_vec[instance_index]);
1086     // make sure all instances have multiple of 2 then SMT mode
1087     // if any of instance doesn't have multiple of 2 then NOT SMT
1088     CF_EXPECT(!smt_vec[instance_index] || cpus_vec[instance_index] % 2 == 0,
1089               "CPUs must be a multiple of 2 in SMT mode");
1090     instance.set_smt(smt_vec[instance_index]);
1091 
1092     // new instance specific flags (moved from common flags)
1093     CF_EXPECT(instance_index < guest_configs.size(),
1094               "instance_index " << instance_index << " out of boundary "
1095                                 << guest_configs.size());
1096     instance.set_target_arch(guest_configs[instance_index].target_arch);
1097     instance.set_guest_android_version(
1098         guest_configs[instance_index].android_version_number);
1099     instance.set_console(console_vec[instance_index]);
1100     instance.set_kgdb(console_vec[instance_index] && kgdb_vec[instance_index]);
1101     instance.set_blank_data_image_mb(blank_data_image_mb_vec[instance_index]);
1102     instance.set_gdb_port(gdb_port_vec[instance_index]);
1103 
1104     std::vector<CuttlefishConfig::DisplayConfig> display_configs;
1105     // assume displays proto input has higher priority than original display inputs
1106     if (!FLAGS_displays_textproto.empty() || !FLAGS_displays_binproto.empty()) {
1107       if (instance_index < instances_display_configs.size()) {
1108         display_configs = instances_display_configs[instance_index];
1109       } // else display_configs is an empty vector
1110     } else {
1111       auto display0 = CF_EXPECT(ParseDisplayConfig(FLAGS_display0));
1112       if (display0) {
1113         display_configs.push_back(*display0);
1114       }
1115       auto display1 = CF_EXPECT(ParseDisplayConfig(FLAGS_display1));
1116       if (display1) {
1117         display_configs.push_back(*display1);
1118       }
1119       auto display2 = CF_EXPECT(ParseDisplayConfig(FLAGS_display2));
1120       if (display2) {
1121         display_configs.push_back(*display2);
1122       }
1123       auto display3 = CF_EXPECT(ParseDisplayConfig(FLAGS_display3));
1124       if (display3) {
1125         display_configs.push_back(*display3);
1126       }
1127     }
1128 
1129     if (x_res_vec[instance_index] > 0 && y_res_vec[instance_index] > 0) {
1130       if (display_configs.empty()) {
1131         display_configs.push_back({
1132             .width = x_res_vec[instance_index],
1133             .height = y_res_vec[instance_index],
1134             .dpi = dpi_vec[instance_index],
1135             .refresh_rate_hz = refresh_rate_hz_vec[instance_index],
1136           });
1137       } else {
1138         LOG(WARNING) << "Ignoring --x_res and --y_res when --displayN specified.";
1139       }
1140     }
1141     instance.set_display_configs(display_configs);
1142 
1143     instance.set_memory_mb(memory_mb_vec[instance_index]);
1144     instance.set_ddr_mem_mb(memory_mb_vec[instance_index] * 1.2);
1145     instance.set_setupwizard_mode(setupwizard_mode_vec[instance_index]);
1146     instance.set_userdata_format(userdata_format_vec[instance_index]);
1147     instance.set_guest_enforce_security(guest_enforce_security_vec[instance_index]);
1148     instance.set_pause_in_bootloader(pause_in_bootloader_vec[instance_index]);
1149     instance.set_run_as_daemon(daemon_vec[instance_index]);
1150     instance.set_enable_modem_simulator(enable_modem_simulator_vec[instance_index] &&
1151                                         !enable_minimal_mode_vec[instance_index]);
1152     instance.set_modem_simulator_instance_number(modem_simulator_count_vec[instance_index]);
1153     instance.set_modem_simulator_sim_type(modem_simulator_sim_type_vec[instance_index]);
1154 
1155     instance.set_enable_minimal_mode(enable_minimal_mode_vec[instance_index]);
1156     instance.set_camera_server_port(camera_server_port_vec[instance_index]);
1157     instance.set_gem5_binary_dir(gem5_binary_dir_vec[instance_index]);
1158     instance.set_gem5_checkpoint_dir(gem5_checkpoint_dir_vec[instance_index]);
1159     instance.set_data_policy(data_policy_vec[instance_index]);
1160 
1161     instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
1162     instance.set_wifi_bridge_name("cvd-wbr");
1163     instance.set_ethernet_bridge_name("cvd-ebr");
1164     instance.set_mobile_tap_name(iface_config.mobile_tap.name);
1165 
1166     if (NetworkInterfaceExists(iface_config.non_bridged_wireless_tap.name) &&
1167         tmp_config_obj.virtio_mac80211_hwsim()) {
1168       instance.set_use_bridged_wifi_tap(false);
1169       instance.set_wifi_tap_name(iface_config.non_bridged_wireless_tap.name);
1170     } else {
1171       instance.set_use_bridged_wifi_tap(true);
1172       instance.set_wifi_tap_name(iface_config.bridged_wireless_tap.name);
1173     }
1174 
1175     instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
1176 
1177     instance.set_uuid(FLAGS_uuid);
1178 
1179     instance.set_modem_simulator_host_id(1000 + num);  // Must be 4 digits
1180     // the deprecated vnc was 6444 + num - 1, and qemu_vnc was vnc - 5900
1181     instance.set_qemu_vnc_server_port(544 + num - 1);
1182     instance.set_adb_host_port(6520 + num - 1);
1183     instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
1184 
1185     instance.set_fastboot_host_port(7520 + num - 1);
1186 
1187     std::uint8_t ethernet_mac[6] = {};
1188     std::uint8_t mobile_mac[6] = {};
1189     std::uint8_t wifi_mac[6] = {};
1190     std::uint8_t ethernet_ipv6[16] = {};
1191     GenerateEthMacForInstance(num - 1, ethernet_mac);
1192     GenerateMobileMacForInstance(num - 1, mobile_mac);
1193     GenerateWifiMacForInstance(num - 1, wifi_mac);
1194     GenerateCorrespondingIpv6ForMac(ethernet_mac, ethernet_ipv6);
1195 
1196     instance.set_ethernet_mac(MacAddressToString(ethernet_mac));
1197     instance.set_mobile_mac(MacAddressToString(mobile_mac));
1198     instance.set_wifi_mac(MacAddressToString(wifi_mac));
1199     instance.set_ethernet_ipv6(Ipv6ToString(ethernet_ipv6));
1200 
1201     instance.set_tombstone_receiver_port(calc_vsock_port(6600));
1202     instance.set_audiocontrol_server_port(9410);  /* OK to use the same port number across instances */
1203     instance.set_config_server_port(calc_vsock_port(6800));
1204 
1205     // gpu related settings
1206     auto gpu_mode = gpu_mode_vec[instance_index];
1207     if (gpu_mode != kGpuModeAuto && gpu_mode != kGpuModeDrmVirgl &&
1208         gpu_mode != kGpuModeGfxstream &&
1209         gpu_mode != kGpuModeGfxstreamGuestAngle &&
1210         gpu_mode != kGpuModeGuestSwiftshader && gpu_mode != kGpuModeNone) {
1211       LOG(FATAL) << "Invalid gpu_mode: " << gpu_mode;
1212     }
1213     if (gpu_mode == kGpuModeAuto) {
1214       if (ShouldEnableAcceleratedRendering(graphics_availability)) {
1215         LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
1216             "rendering support.";
1217         if (vm_manager_vec[0] == QemuManager::name()) {
1218           LOG(INFO) << "Enabling --gpu_mode=drm_virgl.";
1219           gpu_mode = kGpuModeDrmVirgl;
1220         } else {
1221           LOG(INFO) << "Enabling --gpu_mode=gfxstream.";
1222           gpu_mode = kGpuModeGfxstream;
1223         }
1224       } else {
1225         LOG(INFO) << "GPU auto mode: did not detect prerequisites for "
1226             "accelerated rendering support, enabling "
1227             "--gpu_mode=guest_swiftshader.";
1228         gpu_mode = kGpuModeGuestSwiftshader;
1229       }
1230     } else if (gpu_mode == kGpuModeGfxstream ||
1231                gpu_mode == kGpuModeGfxstreamGuestAngle ||
1232                gpu_mode == kGpuModeDrmVirgl) {
1233       if (!ShouldEnableAcceleratedRendering(graphics_availability)) {
1234         LOG(ERROR) << "--gpu_mode=" << gpu_mode
1235                    << " was requested but the prerequisites for accelerated "
1236                       "rendering were not detected so the device may not "
1237                       "function correctly. Please consider switching to "
1238                       "--gpu_mode=auto or --gpu_mode=guest_swiftshader.";
1239       }
1240     }
1241     instance.set_gpu_mode(gpu_mode);
1242 
1243     const auto angle_features = CF_EXPECT(GetNeededAngleFeatures(
1244         CF_EXPECT(GetRenderingMode(gpu_mode)), graphics_availability));
1245     instance.set_gpu_angle_feature_overrides_enabled(
1246         angle_features.angle_feature_overrides_enabled);
1247     instance.set_gpu_angle_feature_overrides_disabled(
1248         angle_features.angle_feature_overrides_disabled);
1249 
1250     instance.set_restart_subprocesses(restart_subprocesses_vec[instance_index]);
1251     instance.set_gpu_capture_binary(gpu_capture_binary_vec[instance_index]);
1252     if (!gpu_capture_binary_vec[instance_index].empty()) {
1253       CF_EXPECT(gpu_mode == kGpuModeGfxstream ||
1254                     gpu_mode == kGpuModeGfxstreamGuestAngle,
1255                 "GPU capture only supported with --gpu_mode=gfxstream");
1256 
1257       // GPU capture runs in a detached mode where the "launcher" process
1258       // intentionally exits immediately.
1259       CF_EXPECT(!restart_subprocesses_vec[instance_index],
1260           "GPU capture only supported with --norestart_subprocesses");
1261     }
1262 
1263     instance.set_hwcomposer(hwcomposer_vec[instance_index]);
1264     if (!hwcomposer_vec[instance_index].empty()) {
1265       if (hwcomposer_vec[instance_index] == kHwComposerRanchu) {
1266         CF_EXPECT(gpu_mode != kGpuModeDrmVirgl,
1267                   "ranchu hwcomposer not supported with --gpu_mode=drm_virgl");
1268       }
1269     }
1270 
1271     if (hwcomposer_vec[instance_index] == kHwComposerAuto) {
1272       if (gpu_mode == kGpuModeDrmVirgl) {
1273         instance.set_hwcomposer(kHwComposerDrm);
1274       } else if (gpu_mode == kGpuModeNone) {
1275         instance.set_hwcomposer(kHwComposerNone);
1276       } else {
1277         instance.set_hwcomposer(kHwComposerRanchu);
1278       }
1279     }
1280 
1281     instance.set_enable_gpu_udmabuf(enable_gpu_udmabuf_vec[instance_index]);
1282 
1283     // 1. Keep original code order SetCommandLineOptionWithMode("enable_sandbox")
1284     // then set_enable_sandbox later.
1285     // 2. SetCommandLineOptionWithMode condition: if gpu_mode or console,
1286     // then SetCommandLineOptionWithMode false as original code did,
1287     // otherwise keep default enable_sandbox value.
1288     // 3. Sepolicy rules need to be updated to support gpu mode. Temporarily disable
1289     // auto-enabling sandbox when gpu is enabled (b/152323505).
1290     default_enable_sandbox += comma_str;
1291     if ((gpu_mode != kGpuModeGuestSwiftshader) || console_vec[instance_index]) {
1292       // original code, just moved to each instance setting block
1293       default_enable_sandbox += "false";
1294     } else {
1295       default_enable_sandbox += BoolToString(enable_sandbox_vec[instance_index]);
1296     }
1297     comma_str = ",";
1298 
1299     auto graphics_check = vmm->ConfigureGraphics(const_instance);
1300     if (!graphics_check.ok()) {
1301       LOG(FATAL) << graphics_check.error().Message();
1302     }
1303 
1304     if (gpu_mode != kGpuModeDrmVirgl && gpu_mode != kGpuModeGfxstream) {
1305       if (vm_manager_vec[0] == QemuManager::name()) {
1306         instance.set_keyboard_server_port(calc_vsock_port(7000));
1307         instance.set_touch_server_port(calc_vsock_port(7100));
1308       }
1309     }
1310     // end of gpu related settings
1311 
1312     instance.set_gnss_grpc_proxy_server_port(7200 + num -1);
1313     instance.set_gnss_file_path(gnss_file_paths[instance_index]);
1314     instance.set_fixed_location_file_path(fixed_location_file_paths[instance_index]);
1315 
1316     std::vector<std::string> virtual_disk_paths;
1317 
1318     bool os_overlay = true;
1319     os_overlay &= !protected_vm_vec[instance_index];
1320     // Gem5 already uses CoW wrappers around disk images
1321     os_overlay &= vm_manager_vec[0] != Gem5Manager::name();
1322     os_overlay &= FLAGS_use_overlay;
1323     if (os_overlay) {
1324       auto path = const_instance.PerInstancePath("overlay.img");
1325       virtual_disk_paths.push_back(path);
1326     } else {
1327       virtual_disk_paths.push_back(const_instance.os_composite_disk_path());
1328     }
1329 
1330     bool persistent_disk = true;
1331     persistent_disk &= !protected_vm_vec[instance_index];
1332     persistent_disk &= vm_manager_vec[0] != Gem5Manager::name();
1333     if (persistent_disk) {
1334       auto path = const_instance.PerInstancePath("persistent_composite.img");
1335       virtual_disk_paths.push_back(path);
1336     }
1337 
1338     instance.set_use_sdcard(use_sdcard_vec[instance_index]);
1339 
1340     bool sdcard = true;
1341     sdcard &= use_sdcard_vec[instance_index];
1342     sdcard &= !protected_vm_vec[instance_index];
1343     if (sdcard) {
1344       virtual_disk_paths.push_back(const_instance.sdcard_path());
1345     }
1346 
1347     instance.set_virtual_disk_paths(virtual_disk_paths);
1348 
1349     // We'd like to set mac prefix to be 5554, 5555, 5556, ... in normal cases.
1350     // When --base_instance_num=3, this might be 5556, 5557, 5558, ... (skipping
1351     // first two)
1352     instance.set_wifi_mac_prefix(5554 + (num - 1));
1353 
1354     // streaming, webrtc setup
1355     instance.set_enable_webrtc(start_webrtc_vec[instance_index]);
1356     instance.set_webrtc_assets_dir(webrtc_assets_dir_vec[instance_index]);
1357 
1358     auto tcp_range  = ParsePortRange(tcp_port_range_vec[instance_index]);
1359     instance.set_webrtc_tcp_port_range(tcp_range);
1360 
1361     auto udp_range  = ParsePortRange(udp_port_range_vec[instance_index]);
1362     instance.set_webrtc_udp_port_range(udp_range);
1363 
1364     // end of streaming, webrtc setup
1365 
1366     instance.set_start_webrtc_signaling_server(false);
1367 
1368     CF_EXPECT(Contains(num_to_webrtc_device_id_flag_map, num),
1369               "Error in looking up num to webrtc_device_id_flag_map");
1370     instance.set_webrtc_device_id(num_to_webrtc_device_id_flag_map[num]);
1371 
1372     if (!is_first_instance || !start_webrtc_vec[instance_index]) {
1373       // Only the first instance starts the signaling server or proxy
1374       instance.set_start_webrtc_signaling_server(false);
1375       instance.set_start_webrtc_sig_server_proxy(false);
1376     } else {
1377       auto port = 8443 + num - 1;
1378       // Change the signaling server port for all instances
1379       tmp_config_obj.set_sig_server_port(port);
1380       // Either the signaling server or the proxy is started, never both
1381       instance.set_start_webrtc_signaling_server(FLAGS_start_webrtc_sig_server);
1382       // The proxy is only started if the host operator is available
1383       instance.set_start_webrtc_sig_server_proxy(
1384           cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH) &&
1385           !FLAGS_start_webrtc_sig_server);
1386     }
1387 
1388     // Start wmediumd process for the first instance if
1389     // vhost_user_mac80211_hwsim is not specified.
1390     const bool start_wmediumd = tmp_config_obj.virtio_mac80211_hwsim() &&
1391                                 FLAGS_vhost_user_mac80211_hwsim.empty() &&
1392                                 is_first_instance;
1393     if (start_wmediumd) {
1394       // TODO(b/199020470) move this to the directory for shared resources
1395       auto vhost_user_socket_path =
1396           const_instance.PerInstanceInternalUdsPath("vhost_user_mac80211");
1397       auto wmediumd_api_socket_path =
1398           const_instance.PerInstanceInternalUdsPath("wmediumd_api_server");
1399 
1400       tmp_config_obj.set_vhost_user_mac80211_hwsim(vhost_user_socket_path);
1401       tmp_config_obj.set_wmediumd_api_server_socket(wmediumd_api_socket_path);
1402       instance.set_start_wmediumd(true);
1403     } else {
1404       instance.set_start_wmediumd(false);
1405     }
1406 
1407     instance.set_start_netsim(is_first_instance && is_any_netsim);
1408 
1409     instance.set_start_rootcanal(is_first_instance && !is_bt_netsim &&
1410                                  (FLAGS_rootcanal_instance_num <= 0));
1411 
1412     instance.set_start_pica(is_first_instance);
1413 
1414     if (!FLAGS_ap_rootfs_image.empty() && !FLAGS_ap_kernel_image.empty() && start_wmediumd) {
1415       // TODO(264537774): Ubuntu grub modules / grub monoliths cannot be used to boot
1416       // 64 bit kernel using 32 bit u-boot / grub.
1417       // Enable this code back after making sure it works across all popular environments
1418       // if (CanGenerateEsp(guest_configs[0].target_arch)) {
1419       //   instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::Grub);
1420       // } else {
1421       //   instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::LegacyDirect);
1422       // }
1423       instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::LegacyDirect);
1424     } else {
1425       instance.set_ap_boot_flow(CuttlefishConfig::InstanceSpecific::APBootFlow::None);
1426     }
1427 
1428     is_first_instance = false;
1429 
1430     // instance.modem_simulator_ports := "" or "[port,]*port"
1431     if (modem_simulator_count_vec[instance_index] > 0) {
1432       std::stringstream modem_ports;
1433       for (auto index {0}; index < modem_simulator_count_vec[instance_index] - 1; index++) {
1434         auto port = 9600 + (modem_simulator_count_vec[instance_index] * (num - 1)) + index;
1435         modem_ports << calc_vsock_port(port) << ",";
1436       }
1437       auto port = 9600 + (modem_simulator_count_vec[instance_index] * (num - 1)) +
1438                   modem_simulator_count_vec[instance_index] - 1;
1439       modem_ports << calc_vsock_port(port);
1440       instance.set_modem_simulator_ports(modem_ports.str());
1441     } else {
1442       instance.set_modem_simulator_ports("");
1443     }
1444     instance_index++;
1445   }  // end of num_instances loop
1446 
1447   std::vector<std::string> names;
1448   names.reserve(tmp_config_obj.Instances().size());
1449   for (const auto& instance : tmp_config_obj.Instances()) {
1450     names.emplace_back(instance.instance_name());
1451   }
1452   tmp_config_obj.set_instance_names(names);
1453 
1454   // keep legacy values for acloud or other related tools (b/262284453)
1455   tmp_config_obj.set_crosvm_binary(crosvm_binary_vec[0]);
1456 
1457   // Keep the original code here to set enable_sandbox commandline flag value
1458   SetCommandLineOptionWithMode("enable_sandbox", default_enable_sandbox.c_str(),
1459                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
1460 
1461   // After SetCommandLineOptionWithMode,
1462   // default flag values changed, need recalculate name_to_default_value
1463   name_to_default_value = CurrentFlagsToDefaultValue();
1464   // After last SetCommandLineOptionWithMode, we could set these special flags
1465   enable_sandbox_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1466       enable_sandbox));
1467 
1468   instance_index = 0;
1469   for (const auto& num : instance_nums) {
1470     auto instance = tmp_config_obj.ForInstance(num);
1471     instance.set_enable_sandbox(enable_sandbox_vec[instance_index]);
1472     instance_index++;
1473   }
1474 
1475   DiskImageFlagsVectorization(tmp_config_obj, fetcher_config);
1476 
1477   return tmp_config_obj;
1478 }
1479 
SetDefaultFlagsForQemu(Arch target_arch,std::map<std::string,std::string> & name_to_default_value)1480 Result<void> SetDefaultFlagsForQemu(Arch target_arch, std::map<std::string, std::string>& name_to_default_value) {
1481   auto instance_nums =
1482       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
1483   int32_t instances_size = instance_nums.size();
1484   std::vector<std::string> gpu_mode_vec =
1485       CF_EXPECT(GET_FLAG_STR_VALUE(gpu_mode));
1486   std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1487       start_webrtc));
1488   std::string default_start_webrtc = "";
1489 
1490   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
1491     if (instance_index > 0) {
1492       default_start_webrtc += ",";
1493     }
1494     if (gpu_mode_vec[instance_index] == kGpuModeGuestSwiftshader && !start_webrtc_vec[instance_index]) {
1495       // This makes WebRTC the default streamer unless the user requests
1496       // another via a --star_<streamer> flag, while at the same time it's
1497       // possible to run without any streamer by setting --start_webrtc=false.
1498       default_start_webrtc += "true";
1499     } else {
1500       default_start_webrtc += BoolToString(start_webrtc_vec[instance_index]);
1501     }
1502   }
1503   // This is the 1st place to set "start_webrtc" flag value
1504   // for now, we don't set non-default options for QEMU
1505   SetCommandLineOptionWithMode("start_webrtc", default_start_webrtc.c_str(),
1506                                SET_FLAGS_DEFAULT);
1507 
1508   std::string default_bootloader =
1509       DefaultHostArtifactsPath("etc/bootloader_");
1510   if(target_arch == Arch::Arm) {
1511       // Bootloader is unstable >512MB RAM on 32-bit ARM
1512       SetCommandLineOptionWithMode("memory_mb", "512", SET_FLAGS_VALUE);
1513       default_bootloader += "arm";
1514   } else if (target_arch == Arch::Arm64) {
1515       default_bootloader += "aarch64";
1516   } else if (target_arch == Arch::RiscV64) {
1517       default_bootloader += "riscv64";
1518   } else {
1519       default_bootloader += "x86_64";
1520   }
1521   default_bootloader += "/bootloader.qemu";
1522   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
1523                                SET_FLAGS_DEFAULT);
1524   return {};
1525 }
1526 
1527 
SetDefaultFlagsForCrosvm(const std::vector<GuestConfig> & guest_configs,std::map<std::string,std::string> & name_to_default_value)1528 Result<void> SetDefaultFlagsForCrosvm(
1529     const std::vector<GuestConfig>& guest_configs,
1530     std::map<std::string, std::string>& name_to_default_value) {
1531   auto instance_nums =
1532       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
1533   int32_t instances_size = instance_nums.size();
1534   std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1535       start_webrtc));
1536   std::string default_start_webrtc = "";
1537 
1538   std::set<Arch> supported_archs{Arch::X86_64};
1539   bool default_enable_sandbox =
1540       supported_archs.find(HostArch()) != supported_archs.end() &&
1541       EnsureDirectoryExists(kCrosvmVarEmptyDir).ok() &&
1542       IsDirectoryEmpty(kCrosvmVarEmptyDir) && !IsRunningInContainer();
1543 
1544   std::vector<std::string> system_image_dir =
1545       android::base::Split(FLAGS_system_image_dir, ",");
1546   std::string cur_bootloader = "";
1547   std::string default_bootloader = "";
1548   std::string default_enable_sandbox_str = "";
1549   for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
1550     if (guest_configs[instance_index].android_version_number == "11.0.0") {
1551       cur_bootloader = DefaultHostArtifactsPath("etc/bootloader_");
1552       if (guest_configs[instance_index].target_arch == Arch::Arm64) {
1553         cur_bootloader += "aarch64";
1554       } else {
1555         cur_bootloader += "x86_64";
1556       }
1557       cur_bootloader += "/bootloader.crosvm";
1558     } else {
1559       if (instance_index >= system_image_dir.size()) {
1560         cur_bootloader = system_image_dir[0];
1561       } else {
1562         cur_bootloader = system_image_dir[instance_index];
1563       }
1564       cur_bootloader += "/bootloader";
1565     }
1566     if (instance_index > 0) {
1567       default_bootloader += ",";
1568       default_enable_sandbox_str += ",";
1569       default_start_webrtc += ",";
1570     }
1571     default_bootloader += cur_bootloader;
1572     default_enable_sandbox_str += BoolToString(default_enable_sandbox);
1573     if (!start_webrtc_vec[instance_index]) {
1574       // This makes WebRTC the default streamer unless the user requests
1575       // another via a --star_<streamer> flag, while at the same time it's
1576       // possible to run without any streamer by setting --start_webrtc=false.
1577       default_start_webrtc += "true";
1578     } else {
1579       default_start_webrtc += BoolToString(start_webrtc_vec[instance_index]);
1580     }
1581   }
1582   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
1583                                SET_FLAGS_DEFAULT);
1584   // This is the 1st place to set "start_webrtc" flag value
1585   SetCommandLineOptionWithMode("start_webrtc", default_start_webrtc.c_str(),
1586                                SET_FLAGS_DEFAULT);
1587   // This is the 1st place to set "enable_sandbox" flag value
1588   SetCommandLineOptionWithMode("enable_sandbox",
1589                                default_enable_sandbox_str.c_str(), SET_FLAGS_DEFAULT);
1590   return {};
1591 }
1592 
SetDefaultFlagsForGem5()1593 void SetDefaultFlagsForGem5() {
1594   // TODO: Add support for gem5 gpu models
1595   SetCommandLineOptionWithMode("gpu_mode", kGpuModeGuestSwiftshader,
1596                                SET_FLAGS_DEFAULT);
1597 
1598   SetCommandLineOptionWithMode("cpus", "1", SET_FLAGS_DEFAULT);
1599 }
1600 
SetDefaultFlagsForOpenwrt(Arch target_arch)1601 void SetDefaultFlagsForOpenwrt(Arch target_arch) {
1602   if (target_arch == Arch::X86_64) {
1603     SetCommandLineOptionWithMode(
1604         "ap_kernel_image",
1605         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_kernel_x86_64")
1606             .c_str(),
1607         SET_FLAGS_DEFAULT);
1608     SetCommandLineOptionWithMode(
1609         "ap_rootfs_image",
1610         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs_x86_64")
1611             .c_str(),
1612         SET_FLAGS_DEFAULT);
1613   } else if (target_arch == Arch::Arm64) {
1614     SetCommandLineOptionWithMode(
1615         "ap_kernel_image",
1616         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_kernel_aarch64")
1617             .c_str(),
1618         SET_FLAGS_DEFAULT);
1619     SetCommandLineOptionWithMode(
1620         "ap_rootfs_image",
1621         DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs_aarch64")
1622             .c_str(),
1623         SET_FLAGS_DEFAULT);
1624   }
1625 }
1626 
GetGuestConfigAndSetDefaults()1627 Result<std::vector<GuestConfig>> GetGuestConfigAndSetDefaults() {
1628   auto instance_nums =
1629       CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
1630   int32_t instances_size = instance_nums.size();
1631   CF_EXPECT(ResolveInstanceFiles(), "Failed to resolve instance files");
1632 
1633   std::vector<GuestConfig> guest_configs = CF_EXPECT(ReadGuestConfig());
1634 
1635   // TODO(weihsu), b/250988697:
1636   // assume all instances are using same VM manager/app/arch,
1637   // later that multiple instances may use different VM manager/app/arch
1638 
1639   // Temporary add this checking to make sure all instances have same target_arch.
1640   // This checking should be removed later.
1641   for (int instance_index = 1; instance_index < guest_configs.size(); instance_index++) {
1642     CF_EXPECT(guest_configs[0].target_arch == guest_configs[instance_index].target_arch,
1643               "all instance target_arch should be same");
1644   }
1645   if (FLAGS_vm_manager == "") {
1646     if (IsHostCompatible(guest_configs[0].target_arch)) {
1647       FLAGS_vm_manager = CrosvmManager::name();
1648     } else {
1649       FLAGS_vm_manager = QemuManager::name();
1650     }
1651   }
1652   // TODO(weihsu), b/250988697:
1653   // Currently, all instances should use same vmm
1654   std::vector<std::string> vm_manager_vec =
1655       android::base::Split(FLAGS_vm_manager, ",");
1656   // get flag default values and store into map
1657   auto name_to_default_value = CurrentFlagsToDefaultValue();
1658 
1659   if (vm_manager_vec[0] == QemuManager::name()) {
1660 
1661     CF_EXPECT(SetDefaultFlagsForQemu(guest_configs[0].target_arch, name_to_default_value));
1662   } else if (vm_manager_vec[0] == CrosvmManager::name()) {
1663     CF_EXPECT(SetDefaultFlagsForCrosvm(guest_configs, name_to_default_value));
1664   } else if (vm_manager_vec[0] == Gem5Manager::name()) {
1665     // TODO: Get the other architectures working
1666     if (guest_configs[0].target_arch != Arch::Arm64) {
1667       return CF_ERR("Gem5 only supports ARM64");
1668     }
1669     SetDefaultFlagsForGem5();
1670   } else {
1671     return CF_ERR("Unknown Virtual Machine Manager: " << FLAGS_vm_manager);
1672   }
1673   if (vm_manager_vec[0] != Gem5Manager::name()) {
1674     // After SetCommandLineOptionWithMode in SetDefaultFlagsForCrosvm/Qemu,
1675     // default flag values changed, need recalculate name_to_default_value
1676     name_to_default_value = CurrentFlagsToDefaultValue();
1677     std::vector<bool> start_webrtc_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(
1678         start_webrtc));
1679     bool start_webrtc = false;
1680     for(bool value : start_webrtc_vec) {
1681       start_webrtc |= value;
1682     }
1683 
1684     auto host_operator_present =
1685         cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH);
1686     // The default for starting signaling server depends on whether or not webrtc
1687     // is to be started and the presence of the host orchestrator.
1688     SetCommandLineOptionWithMode(
1689         "start_webrtc_sig_server",
1690         start_webrtc && !host_operator_present ? "true" : "false",
1691         SET_FLAGS_DEFAULT);
1692     SetCommandLineOptionWithMode(
1693         "webrtc_sig_server_addr",
1694         host_operator_present ? HOST_OPERATOR_SOCKET_PATH : "0.0.0.0",
1695         SET_FLAGS_DEFAULT);
1696   }
1697 
1698   SetDefaultFlagsForOpenwrt(guest_configs[0].target_arch);
1699 
1700   // Set the env variable to empty (in case the caller passed a value for it).
1701   unsetenv(kCuttlefishConfigEnvVarName);
1702 
1703   return guest_configs;
1704 }
1705 
GetConfigFilePath(const CuttlefishConfig & config)1706 std::string GetConfigFilePath(const CuttlefishConfig& config) {
1707   return config.AssemblyPath("cuttlefish_config.json");
1708 }
1709 
GetCuttlefishEnvPath()1710 std::string GetCuttlefishEnvPath() {
1711   return StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
1712 }
1713 
GetSeccompPolicyDir()1714 std::string GetSeccompPolicyDir() {
1715   static const std::string kSeccompDir = std::string("usr/share/crosvm/") +
1716                                          cuttlefish::HostArchStr() +
1717                                          "-linux-gnu/seccomp";
1718   return DefaultHostArtifactsPath(kSeccompDir);
1719 }
1720 
1721 } // namespace cuttlefish
1722