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