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