• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "host/commands/assemble_cvd/flags.h"
2 
3 #include <android-base/logging.h>
4 #include <android-base/strings.h>
5 #include <gflags/gflags.h>
6 #include <json/json.h>
7 #include <json/writer.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 
11 #include <algorithm>
12 #include <array>
13 #include <fstream>
14 #include <iostream>
15 #include <optional>
16 #include <regex>
17 #include <set>
18 #include <sstream>
19 
20 #include "common/libs/utils/environment.h"
21 #include "common/libs/utils/files.h"
22 #include "host/commands/assemble_cvd/alloc.h"
23 #include "host/commands/assemble_cvd/boot_config.h"
24 #include "host/commands/assemble_cvd/clean.h"
25 #include "host/commands/assemble_cvd/disk_flags.h"
26 #include "host/libs/config/host_tools_version.h"
27 #include "host/libs/graphics_detector/graphics_detector.h"
28 #include "host/libs/vm_manager/crosvm_manager.h"
29 #include "host/libs/vm_manager/qemu_manager.h"
30 #include "host/libs/vm_manager/vm_manager.h"
31 
32 using cuttlefish::DefaultHostArtifactsPath;
33 using cuttlefish::HostBinaryPath;
34 using cuttlefish::StringFromEnv;
35 using cuttlefish::vm_manager::CrosvmManager;
36 using google::FlagSettingMode::SET_FLAGS_DEFAULT;
37 
38 DEFINE_string(config, "phone",
39               "Config preset name. Will automatically set flag fields "
40               "using the values from this file of presets. See "
41               "device/google/cuttlefish/shared/config/config_*.json "
42               "for possible values.");
43 
44 DEFINE_int32(cpus, 2, "Virtual CPU count.");
45 DEFINE_string(data_policy, "use_existing", "How to handle userdata partition."
46             " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
47             "'always_create'.");
48 DEFINE_int32(blank_data_image_mb, 0,
49              "The size of the blank data image to generate, MB.");
50 DEFINE_string(blank_data_image_fmt, "f2fs",
51               "The fs format for the blank data image. Used with mkfs.");
52 DEFINE_int32(gdb_port, 0,
53              "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The"
54              "kernel must have been built with CONFIG_RANDOMIZE_BASE "
55              "disabled.");
56 
57 DEFINE_int32(x_res, 0, "Width of the screen in pixels");
58 DEFINE_int32(y_res, 0, "Height of the screen in pixels");
59 DEFINE_int32(dpi, 0, "Pixels per inch for the screen");
60 DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
61 DEFINE_string(kernel_path, "",
62               "Path to the kernel. Overrides the one from the boot image");
63 DEFINE_string(initramfs_path, "", "Path to the initramfs");
64 DEFINE_string(extra_kernel_cmdline, "",
65               "Additional flags to put on the kernel command line");
66 DEFINE_bool(guest_enforce_security, true,
67             "Whether to run in enforcing mode (non permissive).");
68 DEFINE_bool(guest_audit_security, true,
69             "Whether to log security audits.");
70 DEFINE_int32(memory_mb, 0, "Total amount of memory available for guest, MB.");
71 DEFINE_string(serial_number, cuttlefish::ForCurrentInstance("CUTTLEFISHCVD"),
72               "Serial number to use for the device");
73 DEFINE_bool(use_random_serial, false,
74             "Whether to use random serial for the device.");
75 DEFINE_string(vm_manager, "",
76               "What virtual machine manager to use, one of {qemu_cli, crosvm}");
77 DEFINE_string(gpu_mode, cuttlefish::kGpuModeAuto,
78               "What gpu configuration to use, one of {auto, drm_virgl, "
79               "gfxstream, guest_swiftshader}");
80 
81 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
82             " host kernel. This is only used during transition of our clients."
83             " Will be deprecated soon.");
84 DEFINE_bool(start_vnc_server, false, "Whether to start the vnc server process. "
85                                      "The VNC server runs at port 6443 + i for "
86                                      "the vsoc-i user or CUTTLEFISH_INSTANCE=i, "
87                                      "starting from 1.");
88 DEFINE_bool(use_allocd, false,
89             "Acquire static resources from the resource allocator daemon.");
90 DEFINE_bool(enable_minimal_mode, false,
91             "Only enable the minimum features to boot a cuttlefish device and "
92             "support minimal UI interactions.\nNote: Currently only supports "
93             "handheld/phone targets");
94 DEFINE_bool(pause_in_bootloader, false,
95             "Stop the bootflow in u-boot. You can continue the boot by connecting "
96             "to the device console and typing in \"boot\".");
97 DEFINE_bool(enable_host_bluetooth, true,
98             "Enable the root-canal which is Bluetooth emulator in the host.");
99 
100 DEFINE_string(bluetooth_controller_properties_file,
101               "etc/rootcanal/data/controller_properties.json",
102               "The configuartion file path for root-canal which is a Bluetooth "
103               "emulator.");
104 DEFINE_string(
105     bluetooth_default_commands_file, "etc/rootcanal/data/default_commands",
106     "The default commands which root-canal executes when it launches.");
107 
108 /**
109  *
110  * crosvm sandbox feature requires /var/empty and seccomp directory
111  *
112  * --enable-sandbox: will enforce the sandbox feature
113  *                   failing to meet the requirements result in assembly_cvd termination
114  *
115  * --enable-sandbox=no, etc: will disable sandbox
116  *
117  * no option given: it is enabled if /var/empty exists and an empty directory
118  *                             or if it does not exist and can be created
119  *
120  * if seccomp dir doesn't exist, assembly_cvd will terminate
121  *
122  * See SetDefaultFlagsForCrosvm()
123  *
124  */
125 DEFINE_bool(enable_sandbox,
126             false,
127             "Enable crosvm sandbox. Use this when you are sure about what you are doing.");
128 
129 static const std::string kSeccompDir =
130     std::string("usr/share/crosvm/") + cuttlefish::HostArchStr() + "-linux-gnu/seccomp";
131 DEFINE_string(seccomp_policy_dir, DefaultHostArtifactsPath(kSeccompDir),
132               "With sandbox'ed crosvm, overrieds the security comp policy directory");
133 
134 DEFINE_bool(start_webrtc, false, "Whether to start the webrtc process.");
135 
136 DEFINE_string(
137         webrtc_assets_dir, DefaultHostArtifactsPath("usr/share/webrtc/assets"),
138         "[Experimental] Path to WebRTC webpage assets.");
139 
140 DEFINE_string(
141         webrtc_certs_dir, DefaultHostArtifactsPath("usr/share/webrtc/certs"),
142         "[Experimental] Path to WebRTC certificates directory.");
143 
144 DEFINE_string(
145         webrtc_public_ip,
146         "0.0.0.0",
147         "[Deprecated] Ignored, webrtc can figure out its IP address");
148 
149 DEFINE_bool(
150         webrtc_enable_adb_websocket,
151         false,
152         "[Experimental] If enabled, exposes local adb service through a websocket.");
153 
154 DEFINE_bool(
155     start_webrtc_sig_server, false,
156     "Whether to start the webrtc signaling server. This option only applies to "
157     "the first instance, if multiple instances are launched they'll share the "
158     "same signaling server, which is owned by the first one.");
159 
160 DEFINE_string(webrtc_sig_server_addr, "0.0.0.0",
161               "The address of the webrtc signaling server.");
162 
163 DEFINE_int32(
164     webrtc_sig_server_port, 443,
165     "The port of the signaling server if started outside of this launch. If "
166     "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
167     "this parameter is ignored.");
168 
169 // TODO (jemoreira): We need a much bigger range to reliably support several
170 // simultaneous connections.
171 DEFINE_string(tcp_port_range, "15550:15558",
172               "The minimum and maximum TCP port numbers to allocate for ICE "
173               "candidates as 'min:max'. To use any port just specify '0:0'");
174 
175 DEFINE_string(udp_port_range, "15550:15558",
176               "The minimum and maximum UDP port numbers to allocate for ICE "
177               "candidates as 'min:max'. To use any port just specify '0:0'");
178 
179 DEFINE_string(webrtc_sig_server_path, "/register_device",
180               "The path section of the URL where the device should be "
181               "registered with the signaling server.");
182 
183 DEFINE_bool(verify_sig_server_certificate, false,
184             "Whether to verify the signaling server's certificate with a "
185             "trusted signing authority (Disallow self signed certificates).");
186 
187 DEFINE_string(sig_server_headers_file, "",
188               "Path to a file containing HTTP headers to be included in the "
189               "connection to the signaling server. Each header should be on a "
190               "line by itself in the form <name>: <value>");
191 
192 DEFINE_string(
193     webrtc_device_id, "cvd-{num}",
194     "The for the device to register with the signaling server. Every "
195     "appearance of the substring '{num}' in the device id will be substituted "
196     "with the instance number to support multiple instances");
197 
198 DEFINE_string(adb_mode, "vsock_half_tunnel",
199               "Mode for ADB connection."
200               "'vsock_tunnel' for a TCP connection tunneled through vsock, "
201               "'native_vsock' for a  direct connection to the guest ADB over "
202               "vsock, 'vsock_half_tunnel' for a TCP connection forwarded to "
203               "the guest ADB server, or a comma separated list of types as in "
204               "'native_vsock,vsock_half_tunnel'");
205 DEFINE_bool(run_adb_connector, !cuttlefish::IsRunningInContainer(),
206             "Maintain adb connection by sending 'adb connect' commands to the "
207             "server. Only relevant with -adb_mode=tunnel or vsock_tunnel");
208 
209 DEFINE_string(uuid, cuttlefish::ForCurrentInstance(cuttlefish::kDefaultUuidPrefix),
210               "UUID to use for the device. Random if not specified");
211 DEFINE_bool(daemon, false,
212             "Run cuttlefish in background, the launcher exits on boot "
213             "completed/failed");
214 
215 DEFINE_string(device_title, "", "Human readable name for the instance, "
216               "used by the vnc_server for its server title");
217 DEFINE_string(setupwizard_mode, "DISABLED",
218             "One of DISABLED,OPTIONAL,REQUIRED");
219 
220 DEFINE_string(qemu_binary_dir, "/usr/bin",
221               "Path to the directory containing the qemu binary to use");
222 DEFINE_string(crosvm_binary, HostBinaryPath("crosvm"),
223               "The Crosvm binary to use");
224 DEFINE_string(tpm_device, "", "A host TPM device to pass through commands to.");
225 DEFINE_bool(restart_subprocesses, true, "Restart any crashed host process");
226 DEFINE_bool(enable_vehicle_hal_grpc_server, true, "Enables the vehicle HAL "
227             "emulation gRPC server on the host");
228 DEFINE_string(custom_action_config, "",
229               "Path to a custom action config JSON. Defaults to the file provided by "
230               "build variable CVD_CUSTOM_ACTION_CONFIG. If this build variable "
231               "is empty then the custom action config will be empty as well.");
232 DEFINE_string(custom_actions, "",
233               "Serialized JSON of an array of custom action objects (in the "
234               "same format as custom action config JSON files). For use "
235               "within --config preset config files; prefer "
236               "--custom_action_config to specify a custom config file on the "
237               "command line. Actions in this flag are combined with actions "
238               "in --custom_action_config.");
239 DEFINE_string(bootloader, "", "Bootloader binary path");
240 DEFINE_string(boot_slot, "", "Force booting into the given slot. If empty, "
241              "the slot will be chosen based on the misc partition if using a "
242              "bootloader. It will default to 'a' if empty and not using a "
243              "bootloader.");
244 DEFINE_int32(num_instances, 1, "Number of Android guests to launch");
245 DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage "
246             "statistics for metrics collection and analysis.");
247 DEFINE_string(ril_dns, "8.8.8.8", "DNS address of mobile network (RIL)");
248 DEFINE_bool(kgdb, false, "Configure the virtual device for debugging the kernel "
249                          "with kgdb/kdb. The kernel must have been built with "
250                          "kgdb support, and serial console must be enabled.");
251 
252 DEFINE_bool(start_gnss_proxy, false, "Whether to start the gnss proxy.");
253 
254 DEFINE_string(gnss_file_path, "",
255               "Local gnss file path for the gnss proxy");
256 
257 // by default, this modem-simulator is disabled
258 DEFINE_bool(enable_modem_simulator, true,
259             "Enable the modem simulator to process RILD AT commands");
260 // modem_simulator_sim_type=2 for test CtsCarrierApiTestCases
261 DEFINE_int32(modem_simulator_sim_type, 1,
262              "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
263 
264 DEFINE_bool(console, false, "Enable the serial console");
265 
266 DEFINE_bool(vhost_net, false, "Enable vhost acceleration of networking");
267 
268 DEFINE_bool(record_screen, false, "Enable screen recording. "
269                                   "Requires --start_webrtc");
270 
271 DEFINE_bool(ethernet, false, "Enable Ethernet network interface");
272 
273 DEFINE_bool(smt, false, "Enable simultaneous multithreading (SMT/HT)");
274 
275 DEFINE_int32(vsock_guest_cid,
276              cuttlefish::GetDefaultVsockCid(),
277              "vsock_guest_cid is used to determine the guest vsock cid as well as all the ports"
278              "of all vsock servers such as tombstone or modem simulator(s)."
279              "The vsock ports and guest vsock cid are a function of vsock_guest_cid and instance number."
280              "An instance number of i th instance is determined by --num_instances=N and --base_instance_num=B"
281              "The instance number of i th instance is B + i where i in [0, N-1] and B >= 1."
282              "See --num_instances, and --base_instance_num for more information"
283              "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. Otherwise,"
284              "the guest vsock cid is 2 + instance number, which is 2 + (B + i)."
285              "If --vsock_guest_cid is not given, each vsock server port number for i th instance is"
286              "base + instance number - 1. vsock_guest_cid is by default B + i + 2."
287              "Thus, by default, each port is base + vsock_guest_cid - 3."
288              "The same formula holds when --vsock_guest_cid=C is given, for algorithm's sake."
289              "Each vsock server port number is base + C - 3.");
290 
291 DEFINE_string(secure_hals, "keymint,gatekeeper",
292               "Which HALs to use enable host security features for. Supports "
293               "keymint and gatekeeper at the moment.");
294 
295 DEFINE_bool(use_sdcard, true, "Create blank SD-Card image and expose to guest");
296 
297 DEFINE_bool(protected_vm, false, "Boot in Protected VM mode");
298 
299 DEFINE_bool(enable_audio, cuttlefish::HostArch() != cuttlefish::Arch::Arm64,
300             "Whether to play or capture audio");
301 
302 DECLARE_string(assembly_dir);
303 DECLARE_string(boot_image);
304 DECLARE_string(system_image_dir);
305 
306 namespace cuttlefish {
307 using vm_manager::QemuManager;
308 using vm_manager::GetVmManager;
309 
310 namespace {
311 
IsFlagSet(const std::string & flag)312 bool IsFlagSet(const std::string& flag) {
313   return !gflags::GetCommandLineFlagInfoOrDie(flag.c_str()).is_default;
314 }
315 
ParsePortRange(const std::string & flag)316 std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
317   static const std::regex rgx("[0-9]+:[0-9]+");
318   CHECK(std::regex_match(flag, rgx))
319       << "Port range flag has invalid value: " << flag;
320   std::pair<uint16_t, uint16_t> port_range;
321   std::stringstream ss(flag);
322   char c;
323   ss >> port_range.first;
324   ss.read(&c, 1);
325   ss >> port_range.second;
326   return port_range;
327 }
328 
NumStreamers()329 int NumStreamers() {
330   auto start_flags = {FLAGS_start_vnc_server, FLAGS_start_webrtc};
331   return std::count(start_flags.begin(), start_flags.end(), true);
332 }
333 
StrForInstance(const std::string & prefix,int num)334 std::string StrForInstance(const std::string& prefix, int num) {
335   std::ostringstream stream;
336   stream << prefix << std::setfill('0') << std::setw(2) << num;
337   return stream.str();
338 }
339 
340 #ifdef __ANDROID__
ReadKernelConfig(KernelConfig * kernel_config)341 void ReadKernelConfig(KernelConfig* kernel_config) {
342   // QEMU isn't on Android, so always follow host arch
343   kernel_config->target_arch = HostArch();
344   kernel_config->bootconfig_supported = true;
345 }
346 #else
ReadKernelConfig(KernelConfig * kernel_config)347 void ReadKernelConfig(KernelConfig* kernel_config) {
348   // extract-ikconfig can be called directly on the boot image since it looks
349   // for the ikconfig header in the image before extracting the config list.
350   // This code is liable to break if the boot image ever includes the
351   // ikconfig header outside the kernel.
352   const std::string kernel_image_path =
353       FLAGS_kernel_path.size() ? FLAGS_kernel_path : FLAGS_boot_image;
354 
355   Command ikconfig_cmd(HostBinaryPath("extract-ikconfig"));
356   ikconfig_cmd.AddParameter(kernel_image_path);
357 
358   std::string current_path = StringFromEnv("PATH", "");
359   std::string bin_folder = DefaultHostArtifactsPath("bin");
360   ikconfig_cmd.SetEnvironment({"PATH=" + current_path + ":" + bin_folder});
361 
362   std::string ikconfig_path =
363       StringFromEnv("TEMP", "/tmp") + "/ikconfig.XXXXXX";
364   auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path);
365   CHECK(ikconfig_fd->IsOpen())
366       << "Unable to create ikconfig file: " << ikconfig_fd->StrError();
367   ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, ikconfig_fd);
368 
369   auto ikconfig_proc = ikconfig_cmd.Start();
370   CHECK(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0)
371       << "Failed to extract ikconfig from " << kernel_image_path;
372 
373   std::string config = ReadFile(ikconfig_path);
374 
375   if (config.find("\nCONFIG_ARM=y") != std::string::npos) {
376     kernel_config->target_arch = Arch::Arm;
377   } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) {
378     kernel_config->target_arch = Arch::Arm64;
379   } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) {
380     kernel_config->target_arch = Arch::X86_64;
381   } else if (config.find("\nCONFIG_X86=y") != std::string::npos) {
382     kernel_config->target_arch = Arch::X86;
383   } else {
384     LOG(FATAL) << "Unknown target architecture";
385   }
386   kernel_config->bootconfig_supported =
387       config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos;
388 
389   unlink(ikconfig_path.c_str());
390 }
391 #endif  // #ifdef __ANDROID__
392 
393 } // namespace
394 
InitializeCuttlefishConfiguration(const std::string & instance_dir,int modem_simulator_count,KernelConfig kernel_config)395 CuttlefishConfig InitializeCuttlefishConfiguration(
396     const std::string& instance_dir, int modem_simulator_count,
397     KernelConfig kernel_config) {
398   // At most one streamer can be started.
399   CHECK(NumStreamers() <= 1);
400 
401   CuttlefishConfig tmp_config_obj;
402   tmp_config_obj.set_assembly_dir(FLAGS_assembly_dir);
403   tmp_config_obj.set_target_arch(kernel_config.target_arch);
404   tmp_config_obj.set_bootconfig_supported(kernel_config.bootconfig_supported);
405   auto vmm = GetVmManager(FLAGS_vm_manager, kernel_config.target_arch);
406   if (!vmm) {
407     LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
408   }
409   tmp_config_obj.set_vm_manager(FLAGS_vm_manager);
410 
411   const GraphicsAvailability graphics_availability =
412     GetGraphicsAvailabilityWithSubprocessCheck();
413 
414   LOG(VERBOSE) << graphics_availability;
415 
416   tmp_config_obj.set_gpu_mode(FLAGS_gpu_mode);
417 
418   if (tmp_config_obj.gpu_mode() != kGpuModeAuto &&
419       tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
420       tmp_config_obj.gpu_mode() != kGpuModeGfxStream &&
421       tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
422     LOG(FATAL) << "Invalid gpu_mode: " << FLAGS_gpu_mode;
423   }
424   if (tmp_config_obj.gpu_mode() == kGpuModeAuto) {
425     if (ShouldEnableAcceleratedRendering(graphics_availability)) {
426         LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated "
427                      "rendering support.";
428       if (FLAGS_vm_manager == QemuManager::name()) {
429         LOG(INFO) << "Enabling --gpu_mode=drm_virgl.";
430         tmp_config_obj.set_gpu_mode(kGpuModeDrmVirgl);
431       } else {
432         LOG(INFO) << "Enabling --gpu_mode=gfxstream.";
433         tmp_config_obj.set_gpu_mode(kGpuModeGfxStream);
434       }
435     } else {
436       LOG(INFO) << "GPU auto mode: did not detect prerequisites for "
437                    "accelerated rendering support, enabling "
438                    "--gpu_mode=guest_swiftshader.";
439       tmp_config_obj.set_gpu_mode(kGpuModeGuestSwiftshader);
440     }
441   } else if (tmp_config_obj.gpu_mode() == kGpuModeGfxStream ||
442              tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) {
443     if (!ShouldEnableAcceleratedRendering(graphics_availability)) {
444       LOG(ERROR) << "--gpu_mode="
445                  << tmp_config_obj.gpu_mode()
446                  << " was requested but the prerequisites for accelerated "
447                     "rendering were not detected so the device may not "
448                     "function correctly. Please consider switching to "
449                     "--gpu_mode=auto or --gpu_mode=guest_swiftshader.";
450     }
451   }
452   // Sepolicy rules need to be updated to support gpu mode. Temporarily disable
453   // auto-enabling sandbox when gpu is enabled (b/152323505).
454   if (tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) {
455     SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
456   }
457 
458   if (vmm->ConfigureGpuMode(tmp_config_obj.gpu_mode()).empty()) {
459     LOG(FATAL) << "Invalid gpu_mode=" << FLAGS_gpu_mode <<
460                " does not work with vm_manager=" << FLAGS_vm_manager;
461   }
462 
463   CHECK(!FLAGS_smt || FLAGS_cpus % 2 == 0)
464       << "CPUs must be a multiple of 2 in SMT mode";
465   tmp_config_obj.set_cpus(FLAGS_cpus);
466   tmp_config_obj.set_smt(FLAGS_smt);
467 
468   tmp_config_obj.set_memory_mb(FLAGS_memory_mb);
469 
470   tmp_config_obj.set_setupwizard_mode(FLAGS_setupwizard_mode);
471 
472   std::vector<cuttlefish::CuttlefishConfig::DisplayConfig> display_configs = {{
473     .width = FLAGS_x_res,
474     .height = FLAGS_y_res,
475   }};
476   tmp_config_obj.set_display_configs(display_configs);
477   tmp_config_obj.set_dpi(FLAGS_dpi);
478   tmp_config_obj.set_refresh_rate_hz(FLAGS_refresh_rate_hz);
479 
480   auto secure_hals = android::base::Split(FLAGS_secure_hals, ",");
481   tmp_config_obj.set_secure_hals(
482       std::set<std::string>(secure_hals.begin(), secure_hals.end()));
483 
484   tmp_config_obj.set_gdb_port(FLAGS_gdb_port);
485 
486   std::vector<std::string> adb = android::base::Split(FLAGS_adb_mode, ",");
487   tmp_config_obj.set_adb_mode(std::set<std::string>(adb.begin(), adb.end()));
488 
489   tmp_config_obj.set_guest_enforce_security(FLAGS_guest_enforce_security);
490   tmp_config_obj.set_guest_audit_security(FLAGS_guest_audit_security);
491   tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
492 
493   if (FLAGS_console) {
494     SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT);
495   }
496 
497   tmp_config_obj.set_console(FLAGS_console);
498   tmp_config_obj.set_kgdb(FLAGS_console && FLAGS_kgdb);
499 
500   tmp_config_obj.set_host_tools_version(HostToolsCrc());
501 
502   tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
503 
504   tmp_config_obj.set_qemu_binary_dir(FLAGS_qemu_binary_dir);
505   tmp_config_obj.set_crosvm_binary(FLAGS_crosvm_binary);
506   tmp_config_obj.set_tpm_device(FLAGS_tpm_device);
507 
508   tmp_config_obj.set_enable_vnc_server(FLAGS_start_vnc_server);
509 
510   tmp_config_obj.set_seccomp_policy_dir(FLAGS_seccomp_policy_dir);
511 
512   tmp_config_obj.set_enable_webrtc(FLAGS_start_webrtc);
513   tmp_config_obj.set_webrtc_assets_dir(FLAGS_webrtc_assets_dir);
514   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
515   // Note: This will be overridden if the sig server is started by us
516   tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
517   tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
518   tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
519   tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
520   tmp_config_obj.set_sig_server_headers_path(FLAGS_sig_server_headers_file);
521 
522   auto tcp_range  = ParsePortRange(FLAGS_tcp_port_range);
523   tmp_config_obj.set_webrtc_tcp_port_range(tcp_range);
524   auto udp_range  = ParsePortRange(FLAGS_udp_port_range);
525   tmp_config_obj.set_webrtc_udp_port_range(udp_range);
526 
527   tmp_config_obj.set_enable_modem_simulator(FLAGS_enable_modem_simulator &&
528                                             !FLAGS_enable_minimal_mode);
529   tmp_config_obj.set_modem_simulator_instance_number(modem_simulator_count);
530   tmp_config_obj.set_modem_simulator_sim_type(FLAGS_modem_simulator_sim_type);
531 
532   tmp_config_obj.set_webrtc_enable_adb_websocket(
533           FLAGS_webrtc_enable_adb_websocket);
534 
535   tmp_config_obj.set_restart_subprocesses(FLAGS_restart_subprocesses);
536   tmp_config_obj.set_run_adb_connector(FLAGS_run_adb_connector);
537   tmp_config_obj.set_run_as_daemon(FLAGS_daemon);
538 
539   tmp_config_obj.set_data_policy(FLAGS_data_policy);
540   tmp_config_obj.set_blank_data_image_mb(FLAGS_blank_data_image_mb);
541   tmp_config_obj.set_blank_data_image_fmt(FLAGS_blank_data_image_fmt);
542 
543   tmp_config_obj.set_enable_gnss_grpc_proxy(FLAGS_start_gnss_proxy);
544 
545   tmp_config_obj.set_enable_vehicle_hal_grpc_server(FLAGS_enable_vehicle_hal_grpc_server);
546   tmp_config_obj.set_vehicle_hal_grpc_server_binary(
547       HostBinaryPath("android.hardware.automotive.vehicle@2.0-virtualization-grpc-server"));
548 
549   std::string custom_action_config;
550   if (!FLAGS_custom_action_config.empty()) {
551     custom_action_config = FLAGS_custom_action_config;
552   } else {
553     std::string custom_action_config_dir =
554         DefaultHostArtifactsPath("etc/cvd_custom_action_config");
555     if (DirectoryExists(custom_action_config_dir)) {
556       auto custom_action_configs = DirectoryContents(custom_action_config_dir);
557       // Two entries are always . and ..
558       if (custom_action_configs.size() > 3) {
559         LOG(ERROR) << "Expected at most one custom action config in "
560                    << custom_action_config_dir << ". Please delete extras.";
561       } else if (custom_action_configs.size() == 3) {
562         for (const auto& config : custom_action_configs) {
563           if (android::base::EndsWithIgnoreCase(config, ".json")) {
564             custom_action_config = custom_action_config_dir + "/" + config;
565           }
566         }
567       }
568     }
569   }
570   std::vector<CustomActionConfig> custom_actions;
571   Json::CharReaderBuilder builder;
572   Json::Value custom_action_array(Json::arrayValue);
573   if (custom_action_config != "") {
574     // Load the custom action config JSON.
575     std::ifstream ifs(custom_action_config);
576     std::string errorMessage;
577     if (!Json::parseFromStream(builder, ifs, &custom_action_array, &errorMessage)) {
578       LOG(FATAL) << "Could not read custom actions config file "
579                  << custom_action_config << ": "
580                  << errorMessage;
581     }
582     for (const auto& custom_action : custom_action_array) {
583       custom_actions.push_back(CustomActionConfig(custom_action));
584     }
585   }
586   if (FLAGS_custom_actions != "") {
587     // Load the custom action from the --config preset file.
588     std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
589     std::string errorMessage;
590     if (!reader->parse(&*FLAGS_custom_actions.begin(), &*FLAGS_custom_actions.end(),
591                        &custom_action_array, &errorMessage)) {
592       LOG(FATAL) << "Could not read custom actions config flag: "
593                  << errorMessage;
594     }
595     for (const auto& custom_action : custom_action_array) {
596       custom_actions.push_back(CustomActionConfig(custom_action));
597     }
598   }
599   tmp_config_obj.set_custom_actions(custom_actions);
600 
601   tmp_config_obj.set_bootloader(FLAGS_bootloader);
602 
603   tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
604 
605   if (!FLAGS_boot_slot.empty()) {
606       tmp_config_obj.set_boot_slot(FLAGS_boot_slot);
607   }
608 
609   tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath());
610 
611   tmp_config_obj.set_ril_dns(FLAGS_ril_dns);
612 
613   tmp_config_obj.set_enable_minimal_mode(FLAGS_enable_minimal_mode);
614 
615   tmp_config_obj.set_vhost_net(FLAGS_vhost_net);
616 
617   tmp_config_obj.set_record_screen(FLAGS_record_screen);
618 
619   tmp_config_obj.set_ethernet(FLAGS_ethernet);
620 
621   tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth);
622 
623   tmp_config_obj.set_protected_vm(FLAGS_protected_vm);
624 
625   std::vector<int> num_instances;
626   for (int i = 0; i < FLAGS_num_instances; i++) {
627     num_instances.push_back(GetInstance() + i);
628   }
629   std::vector<std::string> gnss_file_paths = android::base::Split(FLAGS_gnss_file_path, ",");
630 
631   bool is_first_instance = true;
632   for (const auto& num : num_instances) {
633     IfaceConfig iface_config;
634     if (FLAGS_use_allocd) {
635       auto iface_opt = AllocateNetworkInterfaces();
636       if (!iface_opt.has_value()) {
637         LOG(FATAL) << "Failed to acquire network interfaces";
638       }
639       iface_config = iface_opt.value();
640     } else {
641       iface_config = DefaultNetworkInterfaces(num);
642     }
643 
644     auto instance = tmp_config_obj.ForInstance(num);
645     auto const_instance =
646         const_cast<const CuttlefishConfig&>(tmp_config_obj)
647             .ForInstance(num);
648     // Set this first so that calls to PerInstancePath below are correct
649     instance.set_instance_dir(instance_dir + "." + std::to_string(num));
650     instance.set_use_allocd(FLAGS_use_allocd);
651     if (FLAGS_use_random_serial) {
652       instance.set_serial_number(
653           RandomSerialNumber("CFCVD" + std::to_string(num)));
654     } else {
655       instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
656     }
657     // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc
658     const auto vsock_guest_cid = FLAGS_vsock_guest_cid + num - GetInstance();
659     instance.set_vsock_guest_cid(vsock_guest_cid);
660     auto calc_vsock_port = [vsock_guest_cid](const int base_port) {
661       // a base (vsock) port is like 9200 for modem_simulator, etc
662       return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid);
663     };
664     instance.set_session_id(iface_config.mobile_tap.session_id);
665 
666     instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
667     instance.set_mobile_tap_name(iface_config.mobile_tap.name);
668     instance.set_wifi_tap_name(iface_config.wireless_tap.name);
669     instance.set_ethernet_tap_name(iface_config.ethernet_tap.name);
670 
671     instance.set_uuid(FLAGS_uuid);
672 
673     instance.set_vnc_server_port(6444 + num - 1);
674     instance.set_host_port(6520 + num - 1);
675     instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
676     instance.set_tombstone_receiver_port(calc_vsock_port(6600));
677     instance.set_vehicle_hal_server_port(9210 + num - 1);
678     instance.set_audiocontrol_server_port(9410);  /* OK to use the same port number across instances */
679     instance.set_config_server_port(calc_vsock_port(6800));
680 
681     if (tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl &&
682         tmp_config_obj.gpu_mode() != kGpuModeGfxStream) {
683         instance.set_frames_server_port(calc_vsock_port(6900));
684       if (FLAGS_vm_manager == QemuManager::name()) {
685         instance.set_keyboard_server_port(calc_vsock_port(7000));
686         instance.set_touch_server_port(calc_vsock_port(7100));
687       }
688     }
689 
690     instance.set_gnss_grpc_proxy_server_port(7200 + num -1);
691 
692     if (num <= gnss_file_paths.size()) {
693       instance.set_gnss_file_path(gnss_file_paths[num-1]);
694     }
695 
696     instance.set_rootcanal_hci_port(7300 + num - 1);
697     instance.set_rootcanal_link_port(7400 + num - 1);
698     instance.set_rootcanal_test_port(7500 + num - 1);
699     instance.set_rootcanal_config_file(
700         FLAGS_bluetooth_controller_properties_file);
701     instance.set_rootcanal_default_commands_file(
702         FLAGS_bluetooth_default_commands_file);
703 
704     instance.set_device_title(FLAGS_device_title);
705 
706     if (FLAGS_protected_vm) {
707       instance.set_virtual_disk_paths(
708           {const_instance.PerInstancePath("os_composite.img")});
709     } else {
710       std::vector<std::string> virtual_disk_paths = {
711           const_instance.PerInstancePath("overlay.img"),
712           const_instance.PerInstancePath("persistent_composite.img"),
713       };
714       if (FLAGS_use_sdcard) {
715         virtual_disk_paths.push_back(const_instance.sdcard_path());
716       }
717       instance.set_virtual_disk_paths(virtual_disk_paths);
718     }
719 
720     std::array<unsigned char, 6> mac_address;
721     mac_address[0] = 1 << 6; // locally administered
722     // TODO(schuffelen): Randomize these and preserve the state.
723     for (int i = 1; i < 5; i++) {
724       mac_address[i] = i;
725     }
726     mac_address[5] = num;
727     instance.set_wifi_mac_address(mac_address);
728 
729     instance.set_start_webrtc_signaling_server(false);
730 
731     if (FLAGS_webrtc_device_id.empty()) {
732       // Use the instance's name as a default
733       instance.set_webrtc_device_id(const_instance.instance_name());
734     } else {
735       std::string device_id = FLAGS_webrtc_device_id;
736       size_t pos;
737       while ((pos = device_id.find("{num}")) != std::string::npos) {
738         device_id.replace(pos, strlen("{num}"), std::to_string(num));
739       }
740       instance.set_webrtc_device_id(device_id);
741     }
742     if (FLAGS_start_webrtc_sig_server && is_first_instance) {
743       auto port = 8443 + num - 1;
744       // Change the signaling server port for all instances
745       tmp_config_obj.set_sig_server_port(port);
746       instance.set_start_webrtc_signaling_server(true);
747     } else {
748       instance.set_start_webrtc_signaling_server(false);
749     }
750     is_first_instance = false;
751 
752     // instance.modem_simulator_ports := "" or "[port,]*port"
753     if (modem_simulator_count > 0) {
754       std::stringstream modem_ports;
755       for (auto index {0}; index < modem_simulator_count - 1; index++) {
756         auto port = 9200 + (modem_simulator_count * (num - 1)) + index;
757         modem_ports << calc_vsock_port(port) << ",";
758       }
759       auto port = 9200 + (modem_simulator_count * (num - 1)) +
760                   modem_simulator_count - 1;
761       modem_ports << calc_vsock_port(port);
762       instance.set_modem_simulator_ports(modem_ports.str());
763     } else {
764       instance.set_modem_simulator_ports("");
765     }
766   } // end of num_instances loop
767 
768   tmp_config_obj.set_enable_sandbox(FLAGS_enable_sandbox);
769 
770   // Audio is not available for VNC server
771   SetCommandLineOptionWithMode(
772       "enable_audio",
773       (FLAGS_start_vnc_server || (cuttlefish::HostArch() == cuttlefish::Arch::Arm64))
774           ? "false"
775           : "true",
776       SET_FLAGS_DEFAULT);
777   tmp_config_obj.set_enable_audio(FLAGS_enable_audio);
778 
779   return tmp_config_obj;
780 }
781 
SetDefaultFlagsFromConfigPreset()782 void SetDefaultFlagsFromConfigPreset() {
783   std::string config_preset = FLAGS_config;  // The name of the preset config.
784   std::string config_file_path;  // The path to the preset config JSON.
785   std::set<std::string> allowed_config_presets;
786   for (const std::string& file :
787        DirectoryContents(DefaultHostArtifactsPath("etc/cvd_config"))) {
788     std::string_view local_file(file);
789     if (android::base::ConsumePrefix(&local_file, "cvd_config_") &&
790         android::base::ConsumeSuffix(&local_file, ".json")) {
791       allowed_config_presets.emplace(local_file);
792     }
793   }
794 
795   // If the user specifies a --config name, then use that config
796   // preset option.
797   std::string android_info_path = FLAGS_system_image_dir + "/android-info.txt";
798   if (IsFlagSet("config")) {
799     if (!allowed_config_presets.count(config_preset)) {
800       LOG(FATAL) << "Invalid --config option '" << config_preset
801                  << "'. Valid options: "
802                  << android::base::Join(allowed_config_presets, ",");
803     }
804   } else if (FileExists(android_info_path)) {
805     // Otherwise try to load the correct preset using android-info.txt.
806     std::ifstream ifs(android_info_path);
807     if (ifs.is_open()) {
808       std::string android_info;
809       ifs >> android_info;
810       std::string_view local_android_info(android_info);
811       if (android::base::ConsumePrefix(&local_android_info, "config=")) {
812         config_preset = local_android_info;
813       }
814       if (!allowed_config_presets.count(config_preset)) {
815         LOG(WARNING) << android_info_path
816                      << " contains invalid config preset: '"
817                      << local_android_info << "'. Defaulting to 'phone'.";
818         config_preset = "phone";
819       }
820     }
821   }
822   LOG(INFO) << "Launching CVD using --config='" << config_preset << "'.";
823 
824   config_file_path = DefaultHostArtifactsPath("etc/cvd_config/cvd_config_" +
825                                               config_preset + ".json");
826   Json::Value config;
827   Json::CharReaderBuilder builder;
828   std::ifstream ifs(config_file_path);
829   std::string errorMessage;
830   if (!Json::parseFromStream(builder, ifs, &config, &errorMessage)) {
831     LOG(FATAL) << "Could not read config file " << config_file_path << ": "
832                << errorMessage;
833   }
834   for (const std::string& flag : config.getMemberNames()) {
835     std::string value;
836     if (flag == "custom_actions") {
837       Json::StreamWriterBuilder factory;
838       value = Json::writeString(factory, config[flag]);
839     } else {
840       value = config[flag].asString();
841     }
842     if (gflags::SetCommandLineOptionWithMode(flag.c_str(), value.c_str(),
843                                              SET_FLAGS_DEFAULT)
844             .empty()) {
845       LOG(FATAL) << "Error setting flag '" << flag << "'.";
846     }
847   }
848 }
849 
SetDefaultFlagsForQemu()850 void SetDefaultFlagsForQemu() {
851   // for now, we don't set non-default options for QEMU
852   if (FLAGS_gpu_mode == kGpuModeGuestSwiftshader && NumStreamers() == 0) {
853     // This makes WebRTC the default streamer unless the user requests
854     // another via a --star_<streamer> flag, while at the same time it's
855     // possible to run without any streamer by setting --start_webrtc=false.
856     SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
857   }
858   std::string default_bootloader = FLAGS_system_image_dir + "/bootloader.qemu";
859   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
860                                SET_FLAGS_DEFAULT);
861 }
862 
SetDefaultFlagsForCrosvm()863 void SetDefaultFlagsForCrosvm() {
864   if (NumStreamers() == 0) {
865     // This makes WebRTC the default streamer unless the user requests
866     // another via a --star_<streamer> flag, while at the same time it's
867     // possible to run without any streamer by setting --start_webrtc=false.
868     SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT);
869   }
870 
871   // TODO(b/182484563): Re-enable autodetection when we fix the crosvm crashes
872   bool default_enable_sandbox = false;
873 
874   SetCommandLineOptionWithMode("enable_sandbox",
875                                (default_enable_sandbox ? "true" : "false"),
876                                SET_FLAGS_DEFAULT);
877 
878   std::string default_bootloader = FLAGS_system_image_dir + "/bootloader";
879   SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(),
880                                SET_FLAGS_DEFAULT);
881 }
882 
ParseCommandLineFlags(int * argc,char *** argv,KernelConfig * kernel_config)883 bool ParseCommandLineFlags(int* argc, char*** argv, KernelConfig* kernel_config) {
884   google::ParseCommandLineNonHelpFlags(argc, argv, true);
885   SetDefaultFlagsFromConfigPreset();
886   google::HandleCommandLineHelpFlags();
887   bool invalid_manager = false;
888 
889   if (!ResolveInstanceFiles()) {
890     return false;
891   }
892 
893   ReadKernelConfig(kernel_config);
894   if (FLAGS_vm_manager == "") {
895     if (IsHostCompatible(kernel_config->target_arch)) {
896       FLAGS_vm_manager = CrosvmManager::name();
897     } else {
898       FLAGS_vm_manager = QemuManager::name();
899     }
900   }
901 
902   if (FLAGS_vm_manager == QemuManager::name()) {
903     SetDefaultFlagsForQemu();
904   } else if (FLAGS_vm_manager == CrosvmManager::name()) {
905     SetDefaultFlagsForCrosvm();
906   } else {
907     std::cerr << "Unknown Virtual Machine Manager: " << FLAGS_vm_manager
908               << std::endl;
909     invalid_manager = true;
910   }
911   // The default for starting signaling server is whether or not webrt is to be
912   // started.
913   SetCommandLineOptionWithMode("start_webrtc_sig_server",
914                                FLAGS_start_webrtc ? "true" : "false",
915                                SET_FLAGS_DEFAULT);
916   if (invalid_manager) {
917     return false;
918   }
919   // Set the env variable to empty (in case the caller passed a value for it).
920   unsetenv(kCuttlefishConfigEnvVarName);
921 
922   return true;
923 }
924 
GetConfigFilePath(const CuttlefishConfig & config)925 std::string GetConfigFilePath(const CuttlefishConfig& config) {
926   return config.AssemblyPath("cuttlefish_config.json");
927 }
928 
GetCuttlefishEnvPath()929 std::string GetCuttlefishEnvPath() {
930   return StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
931 }
932 
933 } // namespace cuttlefish
934