1 #include "host/commands/assemble_cvd/flags.h"
2
3 #include <dirent.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <sys/statvfs.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9
10 #include <algorithm>
11 #include <array>
12 #include <iostream>
13 #include <fstream>
14 #include <regex>
15 #include <set>
16 #include <sstream>
17
18 #include <android-base/strings.h>
19 #include <gflags/gflags.h>
20 #include <android-base/logging.h>
21
22 #include "common/libs/utils/environment.h"
23 #include "common/libs/utils/files.h"
24 #include "common/libs/utils/tee_logging.h"
25 #include "host/commands/assemble_cvd/boot_config.h"
26 #include "host/commands/assemble_cvd/boot_image_unpacker.h"
27 #include "host/commands/assemble_cvd/disk_flags.h"
28 #include "host/commands/assemble_cvd/image_aggregator.h"
29 #include "host/commands/assemble_cvd/assembler_defs.h"
30 #include "host/libs/config/data_image.h"
31 #include "host/libs/config/fetcher_config.h"
32 #include "host/libs/vm_manager/crosvm_manager.h"
33 #include "host/libs/vm_manager/qemu_manager.h"
34 #include "host/libs/vm_manager/vm_manager.h"
35
36 using cuttlefish::CreateBlankImage;
37 using cuttlefish::DataImageResult;
38 using cuttlefish::ForCurrentInstance;
39 using cuttlefish::RandomSerialNumber;
40 using cuttlefish::AssemblerExitCodes;
41 using cuttlefish::vm_manager::CrosvmManager;
42 using cuttlefish::vm_manager::QemuManager;
43 using cuttlefish::vm_manager::VmManager;
44
45 DEFINE_int32(cpus, 2, "Virtual CPU count.");
46 DEFINE_string(data_policy, "use_existing", "How to handle userdata partition."
47 " Either 'use_existing', 'create_if_missing', 'resize_up_to', or "
48 "'always_create'.");
49 DEFINE_int32(blank_data_image_mb, 0,
50 "The size of the blank data image to generate, MB.");
51 DEFINE_string(blank_data_image_fmt, "f2fs",
52 "The fs format for the blank data image. Used with mkfs.");
53 DEFINE_string(qemu_gdb, "",
54 "Debug flag to pass to qemu. e.g. -qemu_gdb=tcp::1234");
55
56 DEFINE_int32(x_res, 720, "Width of the screen in pixels");
57 DEFINE_int32(y_res, 1280, "Height of the screen in pixels");
58 DEFINE_int32(dpi, 160, "Pixels per inch for the screen");
59 DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
60 DEFINE_string(kernel_path, "",
61 "Path to the kernel. Overrides the one from the boot image");
62 DEFINE_string(initramfs_path, "", "Path to the initramfs");
63 DEFINE_bool(decompress_kernel, false,
64 "Whether to decompress the kernel image.");
65 DEFINE_string(extra_kernel_cmdline, "",
66 "Additional flags to put on the kernel command line");
67 DEFINE_int32(loop_max_part, 7, "Maximum number of loop partitions");
68 DEFINE_bool(guest_enforce_security, true,
69 "Whether to run in enforcing mode (non permissive).");
70 DEFINE_bool(guest_audit_security, true,
71 "Whether to log security audits.");
72 DEFINE_bool(guest_force_normal_boot, true,
73 "Whether to force the boot sequence to skip recovery.");
74 DEFINE_int32(memory_mb, 2048,
75 "Total amount of memory available for guest, MB.");
76 DEFINE_string(serial_number, ForCurrentInstance("CUTTLEFISHCVD"),
77 "Serial number to use for the device");
78 DEFINE_bool(use_random_serial, false,
79 "Whether to use random serial for the device.");
80 DEFINE_string(assembly_dir,
81 cuttlefish::StringFromEnv("HOME", ".") + "/cuttlefish_assembly",
82 "A directory to put generated files common between instances");
83 DEFINE_string(instance_dir,
84 cuttlefish::StringFromEnv("HOME", ".") + "/cuttlefish_runtime",
85 "A directory to put all instance specific files");
86 DEFINE_string(
87 vm_manager, CrosvmManager::name(),
88 "What virtual machine manager to use, one of {qemu_cli, crosvm}");
89 DEFINE_string(
90 gpu_mode, cuttlefish::kGpuModeGuestSwiftshader,
91 "What gpu configuration to use, one of {guest_swiftshader, drm_virgl}");
92
93 DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to"
94 " host kernel. This is only used during transition of our clients."
95 " Will be deprecated soon.");
96 DEFINE_bool(start_vnc_server, false, "Whether to start the vnc server process. "
97 "The VNC server runs at port 6443 + i for "
98 "the vsoc-i user or CUTTLEFISH_INSTANCE=i, "
99 "starting from 1.");
100 /**
101 *
102 * crosvm sandbox feature requires /var/empty and seccomp directory
103 *
104 * --enable-sandbox: will enforce the sandbox feature
105 * failing to meet the requirements result in assembly_cvd termination
106 *
107 * --enable-sandbox=no, etc: will disable sandbox
108 *
109 * no option given: it is enabled if /var/empty exists and an empty directory
110 * or if it does not exist and can be created
111 *
112 * if seccomp dir doesn't exist, assembly_cvd will terminate
113 *
114 * See SetDefaultFlagsForCrosvm()
115 *
116 */
117 DEFINE_bool(enable_sandbox,
118 false,
119 "Enable crosvm sandbox. Use this when you are sure about what you are doing.");
120
121 static const std::string kSeccompDir =
122 std::string("usr/share/cuttlefish/") + cuttlefish::HostArch() + "-linux-gnu/seccomp";
123 DEFINE_string(seccomp_policy_dir,
124 cuttlefish::DefaultHostArtifactsPath(kSeccompDir),
125 "With sandbox'ed crosvm, overrieds the security comp policy directory");
126
127 DEFINE_bool(start_webrtc, false, "Whether to start the webrtc process.");
128
129 DEFINE_string(
130 webrtc_assets_dir,
131 cuttlefish::DefaultHostArtifactsPath("usr/share/webrtc/assets"),
132 "[Experimental] Path to WebRTC webpage assets.");
133
134 DEFINE_string(
135 webrtc_certs_dir,
136 cuttlefish::DefaultHostArtifactsPath("usr/share/webrtc/certs"),
137 "[Experimental] Path to WebRTC certificates directory.");
138
139 DEFINE_string(
140 webrtc_public_ip,
141 "127.0.0.1",
142 "[Deprecated] Ignored, webrtc can figure out its IP address");
143
144 DEFINE_bool(
145 webrtc_enable_adb_websocket,
146 false,
147 "[Experimental] If enabled, exposes local adb service through a websocket.");
148
149 DEFINE_bool(
150 start_webrtc_sig_server, false,
151 "Whether to start the webrtc signaling server. This option only applies to "
152 "the first instance, if multiple instances are launched they'll share the "
153 "same signaling server, which is owned by the first one.");
154
155 DEFINE_string(webrtc_sig_server_addr, "127.0.0.1",
156 "The address of the webrtc signaling server.");
157
158 DEFINE_int32(
159 webrtc_sig_server_port, 443,
160 "The port of the signaling server if started outside of this launch. If "
161 "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and "
162 "this parameter is ignored.");
163
164 // TODO (jemoreira): We need a much bigger range to reliably support several
165 // simultaneous connections.
166 DEFINE_string(tcp_port_range, "15550:15558",
167 "The minimum and maximum TCP port numbers to allocate for ICE "
168 "candidates as 'min:max'. To use any port just specify '0:0'");
169
170 DEFINE_string(udp_port_range, "15550:15558",
171 "The minimum and maximum UDP port numbers to allocate for ICE "
172 "candidates as 'min:max'. To use any port just specify '0:0'");
173
174 DEFINE_string(webrtc_sig_server_path, "/register_device",
175 "The path section of the URL where the device should be "
176 "registered with the signaling server.");
177
178 DEFINE_bool(verify_sig_server_certificate, false,
179 "Whether to verify the signaling server's certificate with a "
180 "trusted signing authority (Disallow self signed certificates).");
181
182 DEFINE_string(
183 webrtc_device_id, "cvd-{num}",
184 "The for the device to register with the signaling server. Every "
185 "appearance of the substring '{num}' in the device id will be substituted "
186 "with the instance number to support multiple instances");
187
188 DEFINE_string(adb_mode, "vsock_half_tunnel",
189 "Mode for ADB connection."
190 "'vsock_tunnel' for a TCP connection tunneled through vsock, "
191 "'native_vsock' for a direct connection to the guest ADB over "
192 "vsock, 'vsock_half_tunnel' for a TCP connection forwarded to "
193 "the guest ADB server, or a comma separated list of types as in "
194 "'native_vsock,vsock_half_tunnel'");
195 DEFINE_bool(run_adb_connector, true,
196 "Maintain adb connection by sending 'adb connect' commands to the "
197 "server. Only relevant with -adb_mode=tunnel or vsock_tunnel");
198
199 DEFINE_string(uuid, cuttlefish::ForCurrentInstance(cuttlefish::kDefaultUuidPrefix),
200 "UUID to use for the device. Random if not specified");
201 DEFINE_bool(daemon, false,
202 "Run cuttlefish in background, the launcher exits on boot "
203 "completed/failed");
204
205 DEFINE_string(device_title, "", "Human readable name for the instance, "
206 "used by the vnc_server for its server title");
207 DEFINE_string(setupwizard_mode, "DISABLED",
208 "One of DISABLED,OPTIONAL,REQUIRED");
209
210 DEFINE_string(qemu_binary,
211 "/usr/bin/qemu-system-x86_64",
212 "The qemu binary to use");
213 DEFINE_string(crosvm_binary,
214 cuttlefish::DefaultHostArtifactsPath("bin/crosvm"),
215 "The Crosvm binary to use");
216 DEFINE_string(tpm_binary, "",
217 "The TPM simulator to use. Disabled if empty.");
218 DEFINE_string(tpm_device, "", "A host TPM device to pass through commands to.");
219 DEFINE_bool(restart_subprocesses, true, "Restart any crashed host process");
220 DEFINE_bool(enable_tombstone_receiver, true, "Enables the tombstone logger on "
221 "both the guest and the host");
222 DEFINE_bool(use_bootloader, false, "Boots the device using a bootloader");
223 DEFINE_string(bootloader, "", "Bootloader binary path");
224 DEFINE_string(boot_slot, "", "Force booting into the given slot. If empty, "
225 "the slot will be chosen based on the misc partition if using a "
226 "bootloader. It will default to 'a' if empty and not using a "
227 "bootloader.");
228 DEFINE_int32(num_instances, 1, "Number of Android guests to launch");
229 DEFINE_bool(resume, true, "Resume using the disk from the last session, if "
230 "possible. i.e., if --noresume is passed, the disk "
231 "will be reset to the state it was initially launched "
232 "in. This flag is ignored if the underlying partition "
233 "images have been updated since the first launch.");
234 DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage "
235 "statistics for metrics collection and analysis.");
236 DEFINE_string(ril_dns, "8.8.8.8", "DNS address of mobile network (RIL)");
237 DEFINE_bool(kgdb, false, "Configure the virtual device for debugging the kernel "
238 "with kgdb/kdb. The kernel must have been built with "
239 "kgdb support.");
240
241 // by default, this modem-simulator is disabled
242 DEFINE_bool(enable_modem_simulator, false,
243 "Enable the modem simulator to process RILD AT commands");
244 DEFINE_int32(modem_simulator_count, 1,
245 "Modem simulator count corresponding to maximum sim number");
246
247 namespace {
248
249 const std::string kKernelDefaultPath = "kernel";
250 const std::string kInitramfsImg = "initramfs.img";
251 const std::string kRamdiskConcatExt = ".concat";
252
ParsePortRange(const std::string & flag)253 std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) {
254 static const std::regex rgx("[0-9]+:[0-9]+");
255 CHECK(std::regex_match(flag, rgx))
256 << "Port range flag has invalid value: " << flag;
257 std::pair<uint16_t, uint16_t> port_range;
258 std::stringstream ss(flag);
259 char c;
260 ss >> port_range.first;
261 ss.read(&c, 1);
262 ss >> port_range.second;
263 return port_range;
264 }
265
GetCuttlefishEnvPath()266 std::string GetCuttlefishEnvPath() {
267 return cuttlefish::StringFromEnv("HOME", ".") + "/.cuttlefish.sh";
268 }
269
GetLegacyConfigFilePath(const cuttlefish::CuttlefishConfig & config)270 std::string GetLegacyConfigFilePath(const cuttlefish::CuttlefishConfig& config) {
271 return config.ForDefaultInstance().PerInstancePath("cuttlefish_config.json");
272 }
273
NumStreamers()274 int NumStreamers() {
275 auto start_flags = {FLAGS_start_vnc_server, FLAGS_start_webrtc};
276 return std::count(start_flags.begin(), start_flags.end(), true);
277 }
278
StrForInstance(const std::string & prefix,int num)279 std::string StrForInstance(const std::string& prefix, int num) {
280 std::ostringstream stream;
281 stream << prefix << std::setfill('0') << std::setw(2) << num;
282 return stream.str();
283 }
284
285 // Initializes the config object and saves it to file. It doesn't return it, all
286 // further uses of the config should happen through the singleton
InitializeCuttlefishConfiguration(const cuttlefish::BootImageUnpacker & boot_image_unpacker,const cuttlefish::FetcherConfig & fetcher_config)287 cuttlefish::CuttlefishConfig InitializeCuttlefishConfiguration(
288 const cuttlefish::BootImageUnpacker& boot_image_unpacker,
289 const cuttlefish::FetcherConfig& fetcher_config) {
290 // At most one streamer can be started.
291 CHECK(NumStreamers() <= 1);
292
293 cuttlefish::CuttlefishConfig tmp_config_obj;
294 tmp_config_obj.set_assembly_dir(FLAGS_assembly_dir);
295 if (!VmManager::IsValidName(FLAGS_vm_manager)) {
296 LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
297 }
298 if (!VmManager::IsValidName(FLAGS_vm_manager)) {
299 LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager;
300 }
301 tmp_config_obj.set_vm_manager(FLAGS_vm_manager);
302 tmp_config_obj.set_gpu_mode(FLAGS_gpu_mode);
303 if (VmManager::ConfigureGpuMode(tmp_config_obj.vm_manager(),
304 tmp_config_obj.gpu_mode()).empty()) {
305 LOG(FATAL) << "Invalid gpu_mode=" << FLAGS_gpu_mode <<
306 " does not work with vm_manager=" << FLAGS_vm_manager;
307 }
308
309 tmp_config_obj.set_cpus(FLAGS_cpus);
310 tmp_config_obj.set_memory_mb(FLAGS_memory_mb);
311
312 tmp_config_obj.set_dpi(FLAGS_dpi);
313 tmp_config_obj.set_setupwizard_mode(FLAGS_setupwizard_mode);
314 tmp_config_obj.set_x_res(FLAGS_x_res);
315 tmp_config_obj.set_y_res(FLAGS_y_res);
316 tmp_config_obj.set_refresh_rate_hz(FLAGS_refresh_rate_hz);
317 tmp_config_obj.set_gdb_flag(FLAGS_qemu_gdb);
318 std::vector<std::string> adb = android::base::Split(FLAGS_adb_mode, ",");
319 tmp_config_obj.set_adb_mode(std::set<std::string>(adb.begin(), adb.end()));
320 std::string discovered_kernel = fetcher_config.FindCvdFileWithSuffix(kKernelDefaultPath);
321 std::string foreign_kernel = FLAGS_kernel_path.size() ? FLAGS_kernel_path : discovered_kernel;
322 if (foreign_kernel.size()) {
323 tmp_config_obj.set_kernel_image_path(foreign_kernel);
324 tmp_config_obj.set_use_unpacked_kernel(false);
325 } else {
326 tmp_config_obj.set_kernel_image_path(
327 tmp_config_obj.AssemblyPath(kKernelDefaultPath.c_str()));
328 tmp_config_obj.set_use_unpacked_kernel(true);
329 }
330
331 tmp_config_obj.set_decompress_kernel(FLAGS_decompress_kernel);
332 if (tmp_config_obj.decompress_kernel()) {
333 tmp_config_obj.set_decompressed_kernel_image_path(
334 tmp_config_obj.AssemblyPath("vmlinux"));
335 }
336
337 auto ramdisk_path = tmp_config_obj.AssemblyPath("ramdisk.img");
338 auto vendor_ramdisk_path = tmp_config_obj.AssemblyPath("vendor_ramdisk.img");
339 if (!boot_image_unpacker.HasRamdiskImage()) {
340 LOG(FATAL) << "A ramdisk is required, but the boot image did not have one.";
341 }
342
343 tmp_config_obj.set_boot_image_kernel_cmdline(boot_image_unpacker.kernel_cmdline());
344 tmp_config_obj.set_loop_max_part(FLAGS_loop_max_part);
345 tmp_config_obj.set_guest_enforce_security(FLAGS_guest_enforce_security);
346 tmp_config_obj.set_guest_audit_security(FLAGS_guest_audit_security);
347 tmp_config_obj.set_guest_force_normal_boot(FLAGS_guest_force_normal_boot);
348 tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline);
349
350 std::string vm_manager_cmdline = "";
351 if (FLAGS_vm_manager == QemuManager::name() || FLAGS_use_bootloader) {
352 // crosvm sets up the console= earlycon= pci= reboot= panic= flags for us if
353 // booting straight to the kernel, but QEMU and the bootlaoder via crosvm does not.
354 vm_manager_cmdline += "console=hvc0 pci=noacpi reboot=k panic=-1";
355 if (cuttlefish::HostArch() == "aarch64") {
356 if (FLAGS_vm_manager == QemuManager::name()) {
357 // To update the pl011 address:
358 // $ qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine dumpdtb=virt.dtb
359 // $ dtc -O dts -o virt.dts -I dtb virt.dtb
360 // In the virt.dts file, look for a uart node
361 vm_manager_cmdline += " earlycon=pl011,mmio32,0x9000000";
362 } else {
363 // Crosvm ARM only supports earlycon uart over mmio.
364 vm_manager_cmdline += " earlycon=uart8250,mmio,0x3f8";
365 }
366 } else {
367 // To update the uart8250 address:
368 // $ qemu-system-x86_64 -kernel bzImage -serial stdio | grep ttyS0
369 // Only 'io' mode works; mmio and mmio32 do not
370 vm_manager_cmdline += " earlycon=uart8250,io,0x3f8";
371
372 if (FLAGS_vm_manager == QemuManager::name()) {
373 // crosvm sets up the ramoops.xx= flags for us, but QEMU does not.
374 // See external/crosvm/x86_64/src/lib.rs
375 // this feature is not supported on aarch64
376 vm_manager_cmdline += " ramoops.mem_address=0x100000000";
377 vm_manager_cmdline += " ramoops.mem_size=0x200000";
378 vm_manager_cmdline += " ramoops.console_size=0x80000";
379 vm_manager_cmdline += " ramoops.record_size=0x80000";
380 vm_manager_cmdline += " ramoops.dump_oops=1";
381 }
382 }
383 }
384
385 if (FLAGS_kgdb) {
386 vm_manager_cmdline += " kgdboc_earlycon kgdbcon";
387 // crosvm ARM does not support ttyAMA. ttyAMA is a part of ARM arch.
388 if (FLAGS_vm_manager == QemuManager::name() && cuttlefish::HostArch() == "aarch64") {
389 vm_manager_cmdline += " androidboot.console=ttyAMA0 kgdboc=ttyAMA0";
390 } else {
391 vm_manager_cmdline += " androidboot.console=ttyS0 kgdboc=ttyS0";
392 }
393 } else if (FLAGS_use_bootloader) {
394 // However, if the bootloader is enabled, virtio console can't
395 // be used since uboot doesn't support it.
396 vm_manager_cmdline += " androidboot.console=ttyS1";
397 } else {
398 // If kgdb is disabled, the Android serial console spawns on a
399 // virtio-console port
400 vm_manager_cmdline += " androidboot.console=hvc1";
401 }
402 tmp_config_obj.set_vm_manager_kernel_cmdline(vm_manager_cmdline);
403
404 tmp_config_obj.set_ramdisk_image_path(ramdisk_path);
405 tmp_config_obj.set_vendor_ramdisk_image_path(vendor_ramdisk_path);
406
407 std::string discovered_ramdisk = fetcher_config.FindCvdFileWithSuffix(kInitramfsImg);
408 std::string foreign_ramdisk = FLAGS_initramfs_path.size () ? FLAGS_initramfs_path : discovered_ramdisk;
409 if (foreign_kernel.size() && !foreign_ramdisk.size()) {
410 // If there's a kernel that's passed in without an initramfs, that implies
411 // user error or a kernel built with no modules. In either case, let's
412 // choose to avoid loading the modules from the vendor ramdisk which are
413 // built for the default cf kernel. Once boot occurs, user error will
414 // become obvious.
415 tmp_config_obj.set_final_ramdisk_path(ramdisk_path);
416 } else {
417 tmp_config_obj.set_final_ramdisk_path(ramdisk_path + kRamdiskConcatExt);
418 if(foreign_ramdisk.size()) {
419 tmp_config_obj.set_initramfs_path(foreign_ramdisk);
420 }
421 }
422
423 tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
424 tmp_config_obj.set_logcat_receiver_binary(
425 cuttlefish::DefaultHostArtifactsPath("bin/logcat_receiver"));
426 tmp_config_obj.set_config_server_binary(
427 cuttlefish::DefaultHostArtifactsPath("bin/config_server"));
428
429 tmp_config_obj.set_qemu_binary(FLAGS_qemu_binary);
430 tmp_config_obj.set_crosvm_binary(FLAGS_crosvm_binary);
431 tmp_config_obj.set_tpm_binary(FLAGS_tpm_binary);
432 tmp_config_obj.set_tpm_device(FLAGS_tpm_device);
433 tmp_config_obj.set_console_forwarder_binary(
434 cuttlefish::DefaultHostArtifactsPath("bin/console_forwarder"));
435 tmp_config_obj.set_kernel_log_monitor_binary(
436 cuttlefish::DefaultHostArtifactsPath("bin/kernel_log_monitor"));
437
438 tmp_config_obj.set_enable_vnc_server(FLAGS_start_vnc_server);
439 tmp_config_obj.set_vnc_server_binary(
440 cuttlefish::DefaultHostArtifactsPath("bin/vnc_server"));
441
442 tmp_config_obj.set_enable_sandbox(FLAGS_enable_sandbox);
443
444 tmp_config_obj.set_seccomp_policy_dir(FLAGS_seccomp_policy_dir);
445
446 tmp_config_obj.set_enable_webrtc(FLAGS_start_webrtc);
447 tmp_config_obj.set_webrtc_binary(
448 cuttlefish::DefaultHostArtifactsPath("bin/webRTC"));
449 tmp_config_obj.set_webrtc_assets_dir(FLAGS_webrtc_assets_dir);
450 tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
451 tmp_config_obj.set_sig_server_binary(
452 cuttlefish::DefaultHostArtifactsPath("bin/webrtc_sig_server"));
453 // Note: This will be overridden if the sig server is started by us
454 tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port);
455 tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr);
456 tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path);
457 tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate);
458
459 auto tcp_range = ParsePortRange(FLAGS_tcp_port_range);
460 tmp_config_obj.set_webrtc_tcp_port_range(tcp_range);
461 auto udp_range = ParsePortRange(FLAGS_udp_port_range);
462 tmp_config_obj.set_webrtc_udp_port_range(udp_range);
463
464 tmp_config_obj.set_enable_modem_simulator(FLAGS_enable_modem_simulator);
465 tmp_config_obj.set_modem_simulator_binary(
466 cuttlefish::DefaultHostArtifactsPath("bin/modem_simulator"));
467 tmp_config_obj.set_modem_simulator_instance_number(
468 FLAGS_modem_simulator_count);
469
470 tmp_config_obj.set_webrtc_enable_adb_websocket(
471 FLAGS_webrtc_enable_adb_websocket);
472
473 tmp_config_obj.set_restart_subprocesses(FLAGS_restart_subprocesses);
474 tmp_config_obj.set_run_adb_connector(FLAGS_run_adb_connector);
475 tmp_config_obj.set_adb_connector_binary(
476 cuttlefish::DefaultHostArtifactsPath("bin/adb_connector"));
477 tmp_config_obj.set_socket_vsock_proxy_binary(
478 cuttlefish::DefaultHostArtifactsPath("bin/socket_vsock_proxy"));
479 tmp_config_obj.set_run_as_daemon(FLAGS_daemon);
480
481 tmp_config_obj.set_data_policy(FLAGS_data_policy);
482 tmp_config_obj.set_blank_data_image_mb(FLAGS_blank_data_image_mb);
483 tmp_config_obj.set_blank_data_image_fmt(FLAGS_blank_data_image_fmt);
484
485 tmp_config_obj.set_enable_tombstone_receiver(FLAGS_enable_tombstone_receiver);
486 tmp_config_obj.set_tombstone_receiver_binary(
487 cuttlefish::DefaultHostArtifactsPath("bin/tombstone_receiver"));
488
489 tmp_config_obj.set_use_bootloader(FLAGS_use_bootloader);
490 tmp_config_obj.set_bootloader(FLAGS_bootloader);
491
492 tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats);
493 tmp_config_obj.set_metrics_binary(
494 cuttlefish::DefaultHostArtifactsPath("bin/metrics"));
495
496 if (!FLAGS_boot_slot.empty()) {
497 tmp_config_obj.set_boot_slot(FLAGS_boot_slot);
498 }
499
500 tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath());
501
502 tmp_config_obj.set_ril_dns(FLAGS_ril_dns);
503
504 tmp_config_obj.set_kgdb(FLAGS_kgdb);
505
506 std::vector<int> instance_nums;
507 for (int i = 0; i < FLAGS_num_instances; i++) {
508 instance_nums.push_back(cuttlefish::GetInstance() + i);
509 }
510
511 bool is_first_instance = true;
512 for (const auto& num : instance_nums) {
513 auto instance = tmp_config_obj.ForInstance(num);
514 auto const_instance = const_cast<const cuttlefish::CuttlefishConfig&>(tmp_config_obj)
515 .ForInstance(num);
516 // Set this first so that calls to PerInstancePath below are correct
517 instance.set_instance_dir(FLAGS_instance_dir + "." + std::to_string(num));
518 if(FLAGS_use_random_serial){
519 instance.set_serial_number(RandomSerialNumber("CFCVD" + std::to_string(num)));
520 } else {
521 instance.set_serial_number(FLAGS_serial_number + std::to_string(num));
522 }
523
524 instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num));
525 instance.set_mobile_tap_name(StrForInstance("cvd-mtap-", num));
526
527 instance.set_wifi_tap_name(StrForInstance("cvd-wtap-", num));
528
529 instance.set_vsock_guest_cid(3 + num - 1);
530
531 instance.set_uuid(FLAGS_uuid);
532
533 instance.set_vnc_server_port(6444 + num - 1);
534 instance.set_host_port(6520 + num - 1);
535 instance.set_adb_ip_and_port("127.0.0.1:" + std::to_string(6520 + num - 1));
536 instance.set_tpm_port(2321 + (num * 2) - 2);
537 instance.set_tombstone_receiver_port(6600 + num - 1);
538 instance.set_config_server_port(6800 + num - 1);
539
540 if (FLAGS_gpu_mode != cuttlefish::kGpuModeDrmVirgl &&
541 FLAGS_gpu_mode != cuttlefish::kGpuModeGfxStream) {
542 instance.set_frames_server_port(6900 + num - 1);
543 }
544
545 if (FLAGS_vm_manager == QemuManager::name()) {
546 instance.set_keyboard_server_port(7000 + num - 1);
547 instance.set_touch_server_port(7100 + num - 1);
548 }
549 instance.set_keymaster_vsock_port(7200 + num - 1);
550 instance.set_gatekeeper_vsock_port(7300 + num - 1);
551
552 instance.set_device_title(FLAGS_device_title);
553
554 instance.set_virtual_disk_paths({
555 const_instance.PerInstancePath("overlay.img"),
556 const_instance.sdcard_path(),
557 });
558
559 std::array<unsigned char, 6> mac_address;
560 mac_address[0] = 1 << 6; // locally administered
561 // TODO(schuffelen): Randomize these and preserve the state.
562 for (int i = 1; i < 5; i++) {
563 mac_address[i] = i;
564 }
565 mac_address[5] = num;
566 instance.set_wifi_mac_address(mac_address);
567
568 instance.set_start_webrtc_signaling_server(false);
569
570 if (FLAGS_webrtc_device_id.empty()) {
571 // Use the instance's name as a default
572 instance.set_webrtc_device_id(const_instance.instance_name());
573 } else {
574 std::string device_id = FLAGS_webrtc_device_id;
575 size_t pos;
576 while ((pos = device_id.find("{num}")) != std::string::npos) {
577 device_id.replace(pos, strlen("{num}"), std::to_string(num));
578 }
579 instance.set_webrtc_device_id(device_id);
580 }
581 if (FLAGS_start_webrtc_sig_server && is_first_instance) {
582 auto port = 8443 + num - 1;
583 // Change the signaling server port for all instances
584 tmp_config_obj.set_sig_server_port(port);
585 instance.set_start_webrtc_signaling_server(true);
586 } else {
587 instance.set_start_webrtc_signaling_server(false);
588 }
589 is_first_instance = false;
590 std::stringstream ss;
591 auto base_port = 7200 + num - 2;
592 for (auto index = 0; index < FLAGS_modem_simulator_count; ++index) {
593 ss << base_port + 1 << ",";
594 }
595 std::string modem_simulator_ports = ss.str();
596 modem_simulator_ports.pop_back();
597 instance.set_modem_simulator_ports(modem_simulator_ports);
598 }
599
600 return tmp_config_obj;
601 }
602
SaveConfig(const cuttlefish::CuttlefishConfig & tmp_config_obj)603 bool SaveConfig(const cuttlefish::CuttlefishConfig& tmp_config_obj) {
604 auto config_file = GetConfigFilePath(tmp_config_obj);
605 auto config_link = cuttlefish::GetGlobalConfigFileLink();
606 // Save the config object before starting any host process
607 if (!tmp_config_obj.SaveToFile(config_file)) {
608 LOG(ERROR) << "Unable to save config object";
609 return false;
610 }
611 auto legacy_config_file = GetLegacyConfigFilePath(tmp_config_obj);
612 if (!tmp_config_obj.SaveToFile(legacy_config_file)) {
613 LOG(ERROR) << "Unable to save legacy config object";
614 return false;
615 }
616 setenv(cuttlefish::kCuttlefishConfigEnvVarName, config_file.c_str(), true);
617 if (symlink(config_file.c_str(), config_link.c_str()) != 0) {
618 LOG(ERROR) << "Failed to create symlink to config file at " << config_link
619 << ": " << strerror(errno);
620 return false;
621 }
622
623 return true;
624 }
625
SetDefaultFlagsForQemu()626 void SetDefaultFlagsForQemu() {
627 // for now, we don't set non-default options for QEMU
628 }
629
SetDefaultFlagsForCrosvm()630 void SetDefaultFlagsForCrosvm() {
631 // for now, we support only x86_64 by default
632 bool default_enable_sandbox = false;
633 std::set<const std::string> supported_archs{std::string("x86_64")};
634 if (supported_archs.find(cuttlefish::HostArch()) != supported_archs.end()) {
635 default_enable_sandbox =
636 [](const std::string& var_empty) -> bool {
637 if (cuttlefish::DirectoryExists(var_empty)) {
638 return cuttlefish::IsDirectoryEmpty(var_empty);
639 }
640 if (cuttlefish::FileExists(var_empty)) {
641 return false;
642 }
643 return (::mkdir(var_empty.c_str(), 0755) == 0);
644 }(cuttlefish::kCrosvmVarEmptyDir);
645 }
646
647 // Sepolicy rules need to be updated to support gpu mode. Temporarily disable
648 // auto-enabling sandbox when gpu is enabled (b/152323505).
649 if (FLAGS_gpu_mode != cuttlefish::kGpuModeGuestSwiftshader) {
650 default_enable_sandbox = false;
651 }
652
653 SetCommandLineOptionWithMode("enable_sandbox",
654 (default_enable_sandbox ? "true" : "false"),
655 google::FlagSettingMode::SET_FLAGS_DEFAULT);
656
657 // Crosvm requires a specific setting for kernel decompression; it must be
658 // on for aarch64 and off for x86, no other mode is supported.
659 bool decompress_kernel = false;
660 if (cuttlefish::HostArch() == "aarch64") {
661 decompress_kernel = true;
662 }
663 SetCommandLineOptionWithMode("decompress_kernel",
664 (decompress_kernel ? "true" : "false"),
665 google::FlagSettingMode::SET_FLAGS_DEFAULT);
666 }
667
ParseCommandLineFlags(int * argc,char *** argv)668 bool ParseCommandLineFlags(int* argc, char*** argv) {
669 google::ParseCommandLineNonHelpFlags(argc, argv, true);
670 bool invalid_manager = false;
671 if (FLAGS_vm_manager == QemuManager::name()) {
672 SetDefaultFlagsForQemu();
673 } else if (FLAGS_vm_manager == CrosvmManager::name()) {
674 SetDefaultFlagsForCrosvm();
675 } else {
676 std::cerr << "Unknown Virtual Machine Manager: " << FLAGS_vm_manager
677 << std::endl;
678 invalid_manager = true;
679 }
680 if (NumStreamers() == 0) {
681 // This makes the vnc server the default streamer unless the user requests
682 // another via a --star_<streamer> flag, while at the same time it's
683 // possible to run without any streamer by setting --start_vnc_server=false.
684 SetCommandLineOptionWithMode("start_vnc_server", "true",
685 google::FlagSettingMode::SET_FLAGS_DEFAULT);
686 }
687 // Various temporary workarounds for aarch64
688 if (cuttlefish::HostArch() == "aarch64") {
689 SetCommandLineOptionWithMode("tpm_binary",
690 "",
691 google::FlagSettingMode::SET_FLAGS_DEFAULT);
692 }
693 // The default for starting signaling server is whether or not webrt is to be
694 // started.
695 SetCommandLineOptionWithMode("start_webrtc_sig_server",
696 FLAGS_start_webrtc ? "true" : "false",
697 google::FlagSettingMode::SET_FLAGS_DEFAULT);
698 google::HandleCommandLineHelpFlags();
699 if (invalid_manager) {
700 return false;
701 }
702 // Set the env variable to empty (in case the caller passed a value for it).
703 unsetenv(cuttlefish::kCuttlefishConfigEnvVarName);
704
705 return ResolveInstanceFiles();
706 }
707
cpp_basename(const std::string & str)708 std::string cpp_basename(const std::string& str) {
709 char* copy = strdup(str.c_str()); // basename may modify its argument
710 std::string ret(basename(copy));
711 free(copy);
712 return ret;
713 }
714
CleanPriorFiles(const std::string & path,const std::set<std::string> & preserving)715 bool CleanPriorFiles(const std::string& path, const std::set<std::string>& preserving) {
716 if (preserving.count(cpp_basename(path))) {
717 LOG(DEBUG) << "Preserving: " << path;
718 return true;
719 }
720 struct stat statbuf;
721 if (lstat(path.c_str(), &statbuf) < 0) {
722 int error_num = errno;
723 if (error_num == ENOENT) {
724 return true;
725 } else {
726 LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
727 return false;
728 }
729 }
730 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
731 LOG(DEBUG) << "Deleting: " << path;
732 if (unlink(path.c_str()) < 0) {
733 int error_num = errno;
734 LOG(ERROR) << "Could not unlink \"" << path << "\", error was " << strerror(error_num);
735 return false;
736 }
737 return true;
738 }
739 std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(path.c_str()), closedir);
740 if (!dir) {
741 int error_num = errno;
742 LOG(ERROR) << "Could not clean \"" << path << "\": error was " << strerror(error_num);
743 return false;
744 }
745 for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
746 std::string entity_name(entity->d_name);
747 if (entity_name == "." || entity_name == "..") {
748 continue;
749 }
750 std::string entity_path = path + "/" + entity_name;
751 if (!CleanPriorFiles(entity_path.c_str(), preserving)) {
752 return false;
753 }
754 }
755 if (rmdir(path.c_str()) < 0) {
756 if (!(errno == EEXIST || errno == ENOTEMPTY)) {
757 // If EEXIST or ENOTEMPTY, probably because a file was preserved
758 int error_num = errno;
759 LOG(ERROR) << "Could not rmdir \"" << path << "\", error was " << strerror(error_num);
760 return false;
761 }
762 }
763 return true;
764 }
765
CleanPriorFiles(const std::vector<std::string> & paths,const std::set<std::string> & preserving)766 bool CleanPriorFiles(const std::vector<std::string>& paths, const std::set<std::string>& preserving) {
767 std::string prior_files;
768 for (auto path : paths) {
769 struct stat statbuf;
770 if (stat(path.c_str(), &statbuf) < 0 && errno != ENOENT) {
771 // If ENOENT, it doesn't exist yet, so there is no work to do'
772 int error_num = errno;
773 LOG(ERROR) << "Could not stat \"" << path << "\": " << strerror(error_num);
774 return false;
775 }
776 bool is_directory = (statbuf.st_mode & S_IFMT) == S_IFDIR;
777 prior_files += (is_directory ? (path + "/*") : path) + " ";
778 }
779 LOG(DEBUG) << "Assuming prior files of " << prior_files;
780 std::string lsof_cmd = "lsof -t " + prior_files + " >/dev/null 2>&1";
781 int rval = std::system(lsof_cmd.c_str());
782 // lsof returns 0 if any of the files are open
783 if (WEXITSTATUS(rval) == 0) {
784 LOG(ERROR) << "Clean aborted: files are in use";
785 return false;
786 }
787 for (const auto& path : paths) {
788 if (!CleanPriorFiles(path, preserving)) {
789 LOG(ERROR) << "Remove of file under \"" << path << "\" failed";
790 return false;
791 }
792 }
793 return true;
794 }
795
CleanPriorFiles(const cuttlefish::CuttlefishConfig & config,const std::set<std::string> & preserving)796 bool CleanPriorFiles(const cuttlefish::CuttlefishConfig& config, const std::set<std::string>& preserving) {
797 std::vector<std::string> paths = {
798 // Everything in the assembly directory
799 FLAGS_assembly_dir,
800 // The environment file
801 GetCuttlefishEnvPath(),
802 // The global link to the config file
803 cuttlefish::GetGlobalConfigFileLink(),
804 };
805 for (const auto& instance : config.Instances()) {
806 paths.push_back(instance.instance_dir());
807 }
808 paths.push_back(FLAGS_instance_dir);
809 return CleanPriorFiles(paths, preserving);
810 }
811
ValidateAdbModeFlag(const cuttlefish::CuttlefishConfig & config)812 void ValidateAdbModeFlag(const cuttlefish::CuttlefishConfig& config) {
813 auto adb_modes = config.adb_mode();
814 adb_modes.erase(cuttlefish::AdbMode::Unknown);
815 if (adb_modes.size() < 1) {
816 LOG(INFO) << "ADB not enabled";
817 }
818 }
819
820 } // namespace
821
822 #ifndef O_TMPFILE
823 # define O_TMPFILE (020000000 | O_DIRECTORY)
824 #endif
825
InitFilesystemAndCreateConfig(int * argc,char *** argv,cuttlefish::FetcherConfig fetcher_config)826 const cuttlefish::CuttlefishConfig* InitFilesystemAndCreateConfig(
827 int* argc, char*** argv, cuttlefish::FetcherConfig fetcher_config) {
828 if (!ParseCommandLineFlags(argc, argv)) {
829 LOG(ERROR) << "Failed to parse command arguments";
830 exit(AssemblerExitCodes::kArgumentParsingError);
831 }
832
833 std::string assembly_dir_parent = cuttlefish::AbsolutePath(FLAGS_assembly_dir);
834 while (assembly_dir_parent[assembly_dir_parent.size() - 1] == '/') {
835 assembly_dir_parent =
836 assembly_dir_parent.substr(0, FLAGS_assembly_dir.rfind('/'));
837 }
838 assembly_dir_parent =
839 assembly_dir_parent.substr(0, FLAGS_assembly_dir.rfind('/'));
840 auto log =
841 cuttlefish::SharedFD::Open(
842 assembly_dir_parent,
843 O_WRONLY | O_TMPFILE,
844 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
845 if (!log->IsOpen()) {
846 LOG(ERROR) << "Could not open O_TMPFILE precursor to assemble_cvd.log: "
847 << log->StrError();
848 } else {
849 android::base::SetLogger(cuttlefish::TeeLogger({
850 {cuttlefish::ConsoleSeverity(), cuttlefish::SharedFD::Dup(2)},
851 {cuttlefish::LogFileSeverity(), log},
852 }));
853 }
854
855 auto boot_img_unpacker = CreateBootImageUnpacker();
856 {
857 // The config object is created here, but only exists in memory until the
858 // SaveConfig line below. Don't launch cuttlefish subprocesses between these
859 // two operations, as those will assume they can read the config object from
860 // disk.
861 auto config = InitializeCuttlefishConfiguration(*boot_img_unpacker, fetcher_config);
862 std::set<std::string> preserving;
863 if (FLAGS_resume && ShouldCreateCompositeDisk(config)) {
864 LOG(INFO) << "Requested resuming a previous session (the default behavior) "
865 << "but the base images have changed under the overlay, making the "
866 << "overlay incompatible. Wiping the overlay files.";
867 } else if (FLAGS_resume && !ShouldCreateCompositeDisk(config)) {
868 preserving.insert("overlay.img");
869 preserving.insert("gpt_header.img");
870 preserving.insert("gpt_footer.img");
871 preserving.insert("composite.img");
872 preserving.insert("sdcard.img");
873 preserving.insert("access-kregistry");
874 preserving.insert("disk_hole");
875 preserving.insert("NVChip");
876 preserving.insert("modem_nvram.json");
877 std::stringstream ss;
878 for (int i = 0; i < FLAGS_modem_simulator_count; i++) {
879 ss.clear();
880 ss << "iccprofile_for_sim" << i << ".xml";
881 preserving.insert(ss.str());
882 ss.str("");
883 }
884 }
885 if (!CleanPriorFiles(config, preserving)) {
886 LOG(ERROR) << "Failed to clean prior files";
887 exit(AssemblerExitCodes::kPrioFilesCleanupError);
888 }
889 // Create assembly directory if it doesn't exist.
890 if (!cuttlefish::DirectoryExists(FLAGS_assembly_dir.c_str())) {
891 LOG(DEBUG) << "Setting up " << FLAGS_assembly_dir;
892 if (mkdir(FLAGS_assembly_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
893 && errno != EEXIST) {
894 LOG(ERROR) << "Failed to create assembly directory: "
895 << FLAGS_assembly_dir << ". Error: " << errno;
896 exit(AssemblerExitCodes::kAssemblyDirCreationError);
897 }
898 }
899 if (log->LinkAtCwd(config.AssemblyPath("assemble_cvd.log"))) {
900 LOG(ERROR) << "Unable to persist assemble_cvd log at "
901 << config.AssemblyPath("assemble_cvd.log")
902 << ": " << log->StrError();
903 }
904 std::string disk_hole_dir = FLAGS_assembly_dir + "/disk_hole";
905 if (!cuttlefish::DirectoryExists(disk_hole_dir.c_str())) {
906 LOG(DEBUG) << "Setting up " << disk_hole_dir << "/disk_hole";
907 if (mkdir(disk_hole_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
908 && errno != EEXIST) {
909 LOG(ERROR) << "Failed to create assembly directory: "
910 << disk_hole_dir << ". Error: " << errno;
911 exit(AssemblerExitCodes::kAssemblyDirCreationError);
912 }
913 }
914 for (const auto& instance : config.Instances()) {
915 // Create instance directory if it doesn't exist.
916 if (!cuttlefish::DirectoryExists(instance.instance_dir().c_str())) {
917 LOG(DEBUG) << "Setting up " << FLAGS_instance_dir << ".N";
918 if (mkdir(instance.instance_dir().c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
919 && errno != EEXIST) {
920 LOG(ERROR) << "Failed to create instance directory: "
921 << FLAGS_instance_dir << ". Error: " << errno;
922 exit(AssemblerExitCodes::kInstanceDirCreationError);
923 }
924 }
925 auto internal_dir = instance.instance_dir() + "/" + cuttlefish::kInternalDirName;
926 if (!cuttlefish::DirectoryExists(internal_dir)) {
927 if (mkdir(internal_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
928 && errno != EEXIST) {
929 LOG(ERROR) << "Failed to create internal instance directory: "
930 << internal_dir << ". Error: " << errno;
931 exit(AssemblerExitCodes::kInstanceDirCreationError);
932 }
933 }
934 auto shared_dir = instance.instance_dir() + "/" + cuttlefish::kSharedDirName;
935 if (!cuttlefish::DirectoryExists(shared_dir)) {
936 if (mkdir(shared_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) < 0
937 && errno != EEXIST) {
938 LOG(ERROR) << "Failed to create shared instance directory: "
939 << shared_dir << ". Error: " << errno;
940 exit(AssemblerExitCodes::kInstanceDirCreationError);
941 }
942 }
943 }
944 if (!SaveConfig(config)) {
945 LOG(ERROR) << "Failed to initialize configuration";
946 exit(AssemblerExitCodes::kCuttlefishConfigurationInitError);
947 }
948 }
949
950 std::string first_instance = FLAGS_instance_dir + "." + std::to_string(cuttlefish::GetInstance());
951 if (symlink(first_instance.c_str(), FLAGS_instance_dir.c_str()) < 0) {
952 LOG(ERROR) << "Could not symlink \"" << first_instance << "\" to \"" << FLAGS_instance_dir << "\"";
953 exit(cuttlefish::kCuttlefishConfigurationInitError);
954 }
955
956 // Do this early so that the config object is ready for anything that needs it
957 auto config = cuttlefish::CuttlefishConfig::Get();
958 if (!config) {
959 LOG(ERROR) << "Failed to obtain config singleton";
960 exit(AssemblerExitCodes::kCuttlefishConfigurationInitError);
961 }
962
963 ValidateAdbModeFlag(*config);
964
965 CreateDynamicDiskFiles(fetcher_config, config, boot_img_unpacker.get());
966
967 return config;
968 }
969
GetConfigFilePath(const cuttlefish::CuttlefishConfig & config)970 std::string GetConfigFilePath(const cuttlefish::CuttlefishConfig& config) {
971 return config.AssemblyPath("cuttlefish_config.json");
972 }
973