| #include "host/commands/assemble_cvd/flags.h" |
| |
| #include <android-base/logging.h> |
| #include <android-base/parseint.h> |
| #include <android-base/strings.h> |
| #include <gflags/gflags.h> |
| #include <json/json.h> |
| #include <json/writer.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <algorithm> |
| #include <array> |
| #include <fstream> |
| #include <iostream> |
| #include <optional> |
| #include <regex> |
| #include <set> |
| #include <sstream> |
| #include <unordered_map> |
| |
| #include <fruit/fruit.h> |
| |
| #include "common/libs/utils/environment.h" |
| #include "common/libs/utils/files.h" |
| #include "common/libs/utils/flag_parser.h" |
| #include "host/commands/assemble_cvd/alloc.h" |
| #include "host/commands/assemble_cvd/boot_config.h" |
| #include "host/commands/assemble_cvd/disk_flags.h" |
| #include "host/libs/config/config_flag.h" |
| #include "host/libs/config/host_tools_version.h" |
| #include "host/libs/graphics_detector/graphics_detector.h" |
| #include "host/libs/vm_manager/crosvm_manager.h" |
| #include "host/libs/vm_manager/gem5_manager.h" |
| #include "host/libs/vm_manager/qemu_manager.h" |
| #include "host/libs/vm_manager/vm_manager.h" |
| |
| using cuttlefish::DefaultHostArtifactsPath; |
| using cuttlefish::HostBinaryPath; |
| using cuttlefish::StringFromEnv; |
| using cuttlefish::vm_manager::CrosvmManager; |
| using google::FlagSettingMode::SET_FLAGS_DEFAULT; |
| using google::FlagSettingMode::SET_FLAGS_VALUE; |
| |
| DEFINE_int32(cpus, 2, "Virtual CPU count."); |
| DEFINE_string(data_policy, "use_existing", "How to handle userdata partition." |
| " Either 'use_existing', 'create_if_missing', 'resize_up_to', or " |
| "'always_create'."); |
| DEFINE_int32(blank_data_image_mb, 0, |
| "The size of the blank data image to generate, MB."); |
| DEFINE_int32(gdb_port, 0, |
| "Port number to spawn kernel gdb on e.g. -gdb_port=1234. The" |
| "kernel must have been built with CONFIG_RANDOMIZE_BASE " |
| "disabled."); |
| |
| constexpr const char kDisplayHelp[] = |
| "Comma separated key=value pairs of display properties. Supported " |
| "properties:\n" |
| " 'width': required, width of the display in pixels\n" |
| " 'height': required, height of the display in pixels\n" |
| " 'dpi': optional, default 320, density of the display\n" |
| " 'refresh_rate_hz': optional, default 60, display refresh rate in Hertz\n" |
| ". Example usage: \n" |
| "--display0=width=1280,height=720\n" |
| "--display1=width=1440,height=900,dpi=480,refresh_rate_hz=30\n"; |
| |
| // TODO(b/192495477): combine these into a single repeatable '--display' flag |
| // when assemble_cvd switches to using the new flag parsing library. |
| DEFINE_string(display0, "", kDisplayHelp); |
| DEFINE_string(display1, "", kDisplayHelp); |
| DEFINE_string(display2, "", kDisplayHelp); |
| DEFINE_string(display3, "", kDisplayHelp); |
| |
| // TODO(b/171305898): mark these as deprecated after multi-display is fully |
| // enabled. |
| DEFINE_int32(x_res, 0, "Width of the screen in pixels"); |
| DEFINE_int32(y_res, 0, "Height of the screen in pixels"); |
| DEFINE_int32(dpi, 0, "Pixels per inch for the screen"); |
| DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz"); |
| DEFINE_string(kernel_path, "", |
| "Path to the kernel. Overrides the one from the boot image"); |
| DEFINE_string(initramfs_path, "", "Path to the initramfs"); |
| DEFINE_string(extra_kernel_cmdline, "", |
| "Additional flags to put on the kernel command line"); |
| DEFINE_string(extra_bootconfig_args, "", |
| "Space-separated list of extra bootconfig args. " |
| "Note: overwriting an existing bootconfig argument " |
| "requires ':=' instead of '='."); |
| DEFINE_bool(guest_enforce_security, true, |
| "Whether to run in enforcing mode (non permissive)."); |
| DEFINE_int32(memory_mb, 0, "Total amount of memory available for guest, MB."); |
| DEFINE_string(serial_number, cuttlefish::ForCurrentInstance("CUTTLEFISHCVD"), |
| "Serial number to use for the device"); |
| DEFINE_bool(use_random_serial, false, |
| "Whether to use random serial for the device."); |
| DEFINE_string(vm_manager, "", |
| "What virtual machine manager to use, one of {qemu_cli, crosvm}"); |
| DEFINE_string(gpu_mode, cuttlefish::kGpuModeAuto, |
| "What gpu configuration to use, one of {auto, drm_virgl, " |
| "gfxstream, guest_swiftshader}"); |
| DEFINE_string(hwcomposer, cuttlefish::kHwComposerAuto, |
| "What hardware composer to use, one of {auto, drm, ranchu} "); |
| DEFINE_string(gpu_capture_binary, "", |
| "Path to the GPU capture binary to use when capturing GPU traces" |
| "(ngfx, renderdoc, etc)"); |
| DEFINE_bool(enable_gpu_udmabuf, |
| false, |
| "Use the udmabuf driver for zero-copy virtio-gpu"); |
| |
| DEFINE_bool(enable_gpu_angle, |
| false, |
| "Use ANGLE to provide GLES implementation (always true for" |
| " guest_swiftshader"); |
| DEFINE_bool(deprecated_boot_completed, false, "Log boot completed message to" |
| " host kernel. This is only used during transition of our clients." |
| " Will be deprecated soon."); |
| |
| DEFINE_bool(use_allocd, false, |
| "Acquire static resources from the resource allocator daemon."); |
| DEFINE_bool(enable_minimal_mode, false, |
| "Only enable the minimum features to boot a cuttlefish device and " |
| "support minimal UI interactions.\nNote: Currently only supports " |
| "handheld/phone targets"); |
| DEFINE_bool(pause_in_bootloader, false, |
| "Stop the bootflow in u-boot. You can continue the boot by connecting " |
| "to the device console and typing in \"boot\"."); |
| DEFINE_bool(enable_host_bluetooth, true, |
| "Enable the root-canal which is Bluetooth emulator in the host."); |
| |
| DEFINE_string(bluetooth_controller_properties_file, |
| "etc/rootcanal/data/controller_properties.json", |
| "The configuartion file path for root-canal which is a Bluetooth " |
| "emulator."); |
| DEFINE_string( |
| bluetooth_default_commands_file, "etc/rootcanal/data/default_commands", |
| "The default commands which root-canal executes when it launches."); |
| |
| /** |
| * |
| * crosvm sandbox feature requires /var/empty and seccomp directory |
| * |
| * --enable-sandbox: will enforce the sandbox feature |
| * failing to meet the requirements result in assembly_cvd termination |
| * |
| * --enable-sandbox=no, etc: will disable sandbox |
| * |
| * no option given: it is enabled if /var/empty exists and an empty directory |
| * or if it does not exist and can be created |
| * |
| * if seccomp dir doesn't exist, assembly_cvd will terminate |
| * |
| * See SetDefaultFlagsForCrosvm() |
| * |
| */ |
| DEFINE_bool(enable_sandbox, |
| false, |
| "Enable crosvm sandbox. Use this when you are sure about what you are doing."); |
| |
| static const std::string kSeccompDir = |
| std::string("usr/share/crosvm/") + cuttlefish::HostArchStr() + "-linux-gnu/seccomp"; |
| DEFINE_string(seccomp_policy_dir, DefaultHostArtifactsPath(kSeccompDir), |
| "With sandbox'ed crosvm, overrieds the security comp policy directory"); |
| |
| DEFINE_bool(start_webrtc, false, "Whether to start the webrtc process."); |
| |
| DEFINE_string( |
| webrtc_assets_dir, DefaultHostArtifactsPath("usr/share/webrtc/assets"), |
| "[Experimental] Path to WebRTC webpage assets."); |
| |
| DEFINE_string( |
| webrtc_certs_dir, DefaultHostArtifactsPath("usr/share/webrtc/certs"), |
| "[Experimental] Path to WebRTC certificates directory."); |
| |
| DEFINE_string( |
| webrtc_public_ip, |
| "0.0.0.0", |
| "[Deprecated] Ignored, webrtc can figure out its IP address"); |
| |
| DEFINE_bool( |
| webrtc_enable_adb_websocket, |
| false, |
| "[Experimental] If enabled, exposes local adb service through a websocket."); |
| |
| static constexpr auto HOST_OPERATOR_SOCKET_PATH = "/run/cuttlefish/operator"; |
| |
| DEFINE_bool( |
| // The actual default for this flag is set with SetCommandLineOption() in |
| // GetKernelConfigsAndSetDefaults() at the end of this file. |
| start_webrtc_sig_server, true, |
| "Whether to start the webrtc signaling server. This option only applies to " |
| "the first instance, if multiple instances are launched they'll share the " |
| "same signaling server, which is owned by the first one."); |
| |
| DEFINE_string(webrtc_sig_server_addr, "", |
| "The address of the webrtc signaling server."); |
| |
| DEFINE_int32( |
| webrtc_sig_server_port, 443, |
| "The port of the signaling server if started outside of this launch. If " |
| "-start_webrtc_sig_server is given it will choose 8443+instance_num1-1 and " |
| "this parameter is ignored."); |
| |
| // TODO (jemoreira): We need a much bigger range to reliably support several |
| // simultaneous connections. |
| DEFINE_string(tcp_port_range, "15550:15558", |
| "The minimum and maximum TCP port numbers to allocate for ICE " |
| "candidates as 'min:max'. To use any port just specify '0:0'"); |
| |
| DEFINE_string(udp_port_range, "15550:15558", |
| "The minimum and maximum UDP port numbers to allocate for ICE " |
| "candidates as 'min:max'. To use any port just specify '0:0'"); |
| |
| DEFINE_string(webrtc_sig_server_path, "/register_device", |
| "The path section of the URL where the device should be " |
| "registered with the signaling server."); |
| |
| DEFINE_bool(webrtc_sig_server_secure, true, |
| "Whether the WebRTC signaling server uses secure protocols (WSS vs WS)."); |
| |
| DEFINE_bool(verify_sig_server_certificate, false, |
| "Whether to verify the signaling server's certificate with a " |
| "trusted signing authority (Disallow self signed certificates). " |
| "This is ignored if an insecure server is configured."); |
| |
| DEFINE_string(sig_server_headers_file, "", |
| "Path to a file containing HTTP headers to be included in the " |
| "connection to the signaling server. Each header should be on a " |
| "line by itself in the form <name>: <value>"); |
| |
| DEFINE_string( |
| webrtc_device_id, "cvd-{num}", |
| "The for the device to register with the signaling server. Every " |
| "appearance of the substring '{num}' in the device id will be substituted " |
| "with the instance number to support multiple instances"); |
| |
| DEFINE_string(uuid, cuttlefish::ForCurrentInstance(cuttlefish::kDefaultUuidPrefix), |
| "UUID to use for the device. Random if not specified"); |
| DEFINE_bool(daemon, false, |
| "Run cuttlefish in background, the launcher exits on boot " |
| "completed/failed"); |
| |
| DEFINE_string(setupwizard_mode, "DISABLED", |
| "One of DISABLED,OPTIONAL,REQUIRED"); |
| |
| DEFINE_string(qemu_binary_dir, "/usr/bin", |
| "Path to the directory containing the qemu binary to use"); |
| DEFINE_string(crosvm_binary, HostBinaryPath("crosvm"), |
| "The Crosvm binary to use"); |
| DEFINE_string(gem5_binary_dir, HostBinaryPath("gem5"), |
| "Path to the gem5 build tree root"); |
| DEFINE_bool(restart_subprocesses, true, "Restart any crashed host process"); |
| DEFINE_bool(enable_vehicle_hal_grpc_server, true, "Enables the vehicle HAL " |
| "emulation gRPC server on the host"); |
| DEFINE_string(bootloader, "", "Bootloader binary path"); |
| DEFINE_string(boot_slot, "", "Force booting into the given slot. If empty, " |
| "the slot will be chosen based on the misc partition if using a " |
| "bootloader. It will default to 'a' if empty and not using a " |
| "bootloader."); |
| DEFINE_int32(num_instances, 1, "Number of Android guests to launch"); |
| DEFINE_string(report_anonymous_usage_stats, "", "Report anonymous usage " |
| "statistics for metrics collection and analysis."); |
| DEFINE_string(ril_dns, "8.8.8.8", "DNS address of mobile network (RIL)"); |
| DEFINE_bool(kgdb, false, "Configure the virtual device for debugging the kernel " |
| "with kgdb/kdb. The kernel must have been built with " |
| "kgdb support, and serial console must be enabled."); |
| |
| DEFINE_bool(start_gnss_proxy, false, "Whether to start the gnss proxy."); |
| |
| DEFINE_string(gnss_file_path, "", |
| "Local gnss file path for the gnss proxy"); |
| |
| // by default, this modem-simulator is disabled |
| DEFINE_bool(enable_modem_simulator, true, |
| "Enable the modem simulator to process RILD AT commands"); |
| // modem_simulator_sim_type=2 for test CtsCarrierApiTestCases |
| DEFINE_int32(modem_simulator_sim_type, 1, |
| "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases"); |
| |
| DEFINE_bool(console, false, "Enable the serial console"); |
| |
| DEFINE_bool(vhost_net, false, "Enable vhost acceleration of networking"); |
| |
| DEFINE_string( |
| vhost_user_mac80211_hwsim, "", |
| "Unix socket path for vhost-user of mac80211_hwsim, typically served by " |
| "wmediumd. You can set this when using an external wmediumd instance."); |
| DEFINE_string(wmediumd_config, "", |
| "Path to the wmediumd config file. When missing, the default " |
| "configuration is used which adds MAC addresses for up to 16 " |
| "cuttlefish instances including AP."); |
| DEFINE_string(ap_rootfs_image, |
| DefaultHostArtifactsPath("etc/openwrt/images/openwrt_rootfs"), |
| "rootfs image for AP instance"); |
| DEFINE_string(ap_kernel_image, |
| DefaultHostArtifactsPath("etc/openwrt/images/kernel_for_openwrt"), |
| "kernel image for AP instance"); |
| |
| DEFINE_bool(record_screen, false, "Enable screen recording. " |
| "Requires --start_webrtc"); |
| |
| DEFINE_bool(smt, false, "Enable simultaneous multithreading (SMT/HT)"); |
| |
| DEFINE_int32(vsock_guest_cid, |
| cuttlefish::GetDefaultVsockCid(), |
| "vsock_guest_cid is used to determine the guest vsock cid as well as all the ports" |
| "of all vsock servers such as tombstone or modem simulator(s)." |
| "The vsock ports and guest vsock cid are a function of vsock_guest_cid and instance number." |
| "An instance number of i th instance is determined by --num_instances=N and --base_instance_num=B" |
| "The instance number of i th instance is B + i where i in [0, N-1] and B >= 1." |
| "See --num_instances, and --base_instance_num for more information" |
| "If --vsock_guest_cid=C is given and C >= 3, the guest vsock cid is C + i. Otherwise," |
| "the guest vsock cid is 2 + instance number, which is 2 + (B + i)." |
| "If --vsock_guest_cid is not given, each vsock server port number for i th instance is" |
| "base + instance number - 1. vsock_guest_cid is by default B + i + 2." |
| "Thus, by default, each port is base + vsock_guest_cid - 3." |
| "The same formula holds when --vsock_guest_cid=C is given, for algorithm's sake." |
| "Each vsock server port number is base + C - 3."); |
| |
| DEFINE_string(secure_hals, "keymint,gatekeeper", |
| "Which HALs to use enable host security features for. Supports " |
| "keymint and gatekeeper at the moment."); |
| |
| DEFINE_bool(use_sdcard, true, "Create blank SD-Card image and expose to guest"); |
| |
| DEFINE_bool(protected_vm, false, "Boot in Protected VM mode"); |
| |
| DEFINE_bool(enable_audio, cuttlefish::HostArch() != cuttlefish::Arch::Arm64, |
| "Whether to play or capture audio"); |
| |
| DEFINE_uint32(camera_server_port, 0, "camera vsock port"); |
| |
| DEFINE_string(userdata_format, "f2fs", "The userdata filesystem format"); |
| |
| DECLARE_string(assembly_dir); |
| DECLARE_string(boot_image); |
| DECLARE_string(system_image_dir); |
| |
| namespace cuttlefish { |
| using vm_manager::QemuManager; |
| using vm_manager::Gem5Manager; |
| using vm_manager::GetVmManager; |
| |
| namespace { |
| |
| std::pair<uint16_t, uint16_t> ParsePortRange(const std::string& flag) { |
| static const std::regex rgx("[0-9]+:[0-9]+"); |
| CHECK(std::regex_match(flag, rgx)) |
| << "Port range flag has invalid value: " << flag; |
| std::pair<uint16_t, uint16_t> port_range; |
| std::stringstream ss(flag); |
| char c; |
| ss >> port_range.first; |
| ss.read(&c, 1); |
| ss >> port_range.second; |
| return port_range; |
| } |
| |
| std::string StrForInstance(const std::string& prefix, int num) { |
| std::ostringstream stream; |
| stream << prefix << std::setfill('0') << std::setw(2) << num; |
| return stream.str(); |
| } |
| |
| std::optional<CuttlefishConfig::DisplayConfig> ParseDisplayConfig( |
| const std::string& flag) { |
| if (flag.empty()) { |
| return std::nullopt; |
| } |
| |
| std::unordered_map<std::string, std::string> props; |
| |
| const std::vector<std::string> pairs = android::base::Split(flag, ","); |
| for (const std::string& pair : pairs) { |
| const std::vector<std::string> keyvalue = android::base::Split(pair, "="); |
| CHECK_EQ(2, keyvalue.size()) << "Invalid display: " << flag; |
| |
| const std::string& prop_key = keyvalue[0]; |
| const std::string& prop_val = keyvalue[1]; |
| props[prop_key] = prop_val; |
| } |
| |
| CHECK(props.find("width") != props.end()) |
| << "Display configuration missing 'width' in " << flag; |
| CHECK(props.find("height") != props.end()) |
| << "Display configuration missing 'height' in " << flag; |
| |
| int display_width; |
| CHECK(android::base::ParseInt(props["width"], &display_width)) |
| << "Display configuration invalid 'width' in " << flag; |
| |
| int display_height; |
| CHECK(android::base::ParseInt(props["height"], &display_height)) |
| << "Display configuration invalid 'height' in " << flag; |
| |
| int display_dpi = 320; |
| auto display_dpi_it = props.find("dpi"); |
| if (display_dpi_it != props.end()) { |
| CHECK(android::base::ParseInt(display_dpi_it->second, &display_dpi)) |
| << "Display configuration invalid 'dpi' in " << flag; |
| } |
| |
| int display_refresh_rate_hz = 60; |
| auto display_refresh_rate_hz_it = props.find("refresh_rate_hz"); |
| if (display_refresh_rate_hz_it != props.end()) { |
| CHECK(android::base::ParseInt(display_refresh_rate_hz_it->second, |
| &display_refresh_rate_hz)) |
| << "Display configuration invalid 'refresh_rate_hz' in " << flag; |
| } |
| |
| return CuttlefishConfig::DisplayConfig{ |
| .width = display_width, |
| .height = display_height, |
| .dpi = display_dpi, |
| .refresh_rate_hz = display_refresh_rate_hz, |
| }; |
| } |
| |
| #ifdef __ANDROID__ |
| Result<KernelConfig> ReadKernelConfig() { |
| // QEMU isn't on Android, so always follow host arch |
| KernelConfig ret{}; |
| ret.target_arch = HostArch(); |
| ret.bootconfig_supported = true; |
| return ret; |
| } |
| #else |
| Result<KernelConfig> ReadKernelConfig() { |
| // extract-ikconfig can be called directly on the boot image since it looks |
| // for the ikconfig header in the image before extracting the config list. |
| // This code is liable to break if the boot image ever includes the |
| // ikconfig header outside the kernel. |
| const std::string kernel_image_path = |
| FLAGS_kernel_path.size() ? FLAGS_kernel_path : FLAGS_boot_image; |
| |
| Command ikconfig_cmd(HostBinaryPath("extract-ikconfig")); |
| ikconfig_cmd.AddParameter(kernel_image_path); |
| |
| std::string current_path = StringFromEnv("PATH", ""); |
| std::string bin_folder = DefaultHostArtifactsPath("bin"); |
| ikconfig_cmd.SetEnvironment({"PATH=" + current_path + ":" + bin_folder}); |
| |
| std::string ikconfig_path = |
| StringFromEnv("TEMP", "/tmp") + "/ikconfig.XXXXXX"; |
| auto ikconfig_fd = SharedFD::Mkstemp(&ikconfig_path); |
| CF_EXPECT(ikconfig_fd->IsOpen(), |
| "Unable to create ikconfig file: " << ikconfig_fd->StrError()); |
| ikconfig_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, ikconfig_fd); |
| |
| auto ikconfig_proc = ikconfig_cmd.Start(); |
| CF_EXPECT(ikconfig_proc.Started() && ikconfig_proc.Wait() == 0, |
| "Failed to extract ikconfig from " << kernel_image_path); |
| |
| std::string config = ReadFile(ikconfig_path); |
| |
| KernelConfig kernel_config; |
| if (config.find("\nCONFIG_ARM=y") != std::string::npos) { |
| kernel_config.target_arch = Arch::Arm; |
| } else if (config.find("\nCONFIG_ARM64=y") != std::string::npos) { |
| kernel_config.target_arch = Arch::Arm64; |
| } else if (config.find("\nCONFIG_X86_64=y") != std::string::npos) { |
| kernel_config.target_arch = Arch::X86_64; |
| } else if (config.find("\nCONFIG_X86=y") != std::string::npos) { |
| kernel_config.target_arch = Arch::X86; |
| } else { |
| return CF_ERR("Unknown target architecture"); |
| } |
| kernel_config.bootconfig_supported = |
| config.find("\nCONFIG_BOOT_CONFIG=y") != std::string::npos; |
| |
| unlink(ikconfig_path.c_str()); |
| return kernel_config; |
| } |
| #endif // #ifdef __ANDROID__ |
| |
| } // namespace |
| |
| CuttlefishConfig InitializeCuttlefishConfiguration( |
| const std::string& root_dir, int modem_simulator_count, |
| KernelConfig kernel_config, fruit::Injector<>& injector) { |
| CuttlefishConfig tmp_config_obj; |
| |
| for (const auto& fragment : injector.getMultibindings<ConfigFragment>()) { |
| CHECK(tmp_config_obj.SaveFragment(*fragment)) |
| << "Failed to save fragment " << fragment->Name(); |
| } |
| |
| tmp_config_obj.set_root_dir(root_dir); |
| |
| tmp_config_obj.set_target_arch(kernel_config.target_arch); |
| tmp_config_obj.set_bootconfig_supported(kernel_config.bootconfig_supported); |
| auto vmm = GetVmManager(FLAGS_vm_manager, kernel_config.target_arch); |
| if (!vmm) { |
| LOG(FATAL) << "Invalid vm_manager: " << FLAGS_vm_manager; |
| } |
| tmp_config_obj.set_vm_manager(FLAGS_vm_manager); |
| |
| std::vector<CuttlefishConfig::DisplayConfig> display_configs; |
| |
| auto display0 = ParseDisplayConfig(FLAGS_display0); |
| if (display0) { |
| display_configs.push_back(*display0); |
| } |
| auto display1 = ParseDisplayConfig(FLAGS_display1); |
| if (display1) { |
| display_configs.push_back(*display1); |
| } |
| auto display2 = ParseDisplayConfig(FLAGS_display2); |
| if (display2) { |
| display_configs.push_back(*display2); |
| } |
| auto display3 = ParseDisplayConfig(FLAGS_display3); |
| if (display3) { |
| display_configs.push_back(*display3); |
| } |
| |
| if (FLAGS_x_res > 0 && FLAGS_y_res > 0) { |
| if (display_configs.empty()) { |
| display_configs.push_back({ |
| .width = FLAGS_x_res, |
| .height = FLAGS_y_res, |
| .dpi = FLAGS_dpi, |
| .refresh_rate_hz = FLAGS_refresh_rate_hz, |
| }); |
| } else { |
| LOG(WARNING) << "Ignoring --x_res and --y_res when --displayN specified."; |
| } |
| } |
| |
| tmp_config_obj.set_display_configs(display_configs); |
| |
| const GraphicsAvailability graphics_availability = |
| GetGraphicsAvailabilityWithSubprocessCheck(); |
| |
| LOG(DEBUG) << graphics_availability; |
| |
| tmp_config_obj.set_gpu_mode(FLAGS_gpu_mode); |
| if (tmp_config_obj.gpu_mode() != kGpuModeAuto && |
| tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl && |
| tmp_config_obj.gpu_mode() != kGpuModeGfxStream && |
| tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) { |
| LOG(FATAL) << "Invalid gpu_mode: " << FLAGS_gpu_mode; |
| } |
| if (tmp_config_obj.gpu_mode() == kGpuModeAuto) { |
| if (ShouldEnableAcceleratedRendering(graphics_availability)) { |
| LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated " |
| "rendering support."; |
| if (FLAGS_vm_manager == QemuManager::name()) { |
| LOG(INFO) << "Enabling --gpu_mode=drm_virgl."; |
| tmp_config_obj.set_gpu_mode(kGpuModeDrmVirgl); |
| } else { |
| LOG(INFO) << "Enabling --gpu_mode=gfxstream."; |
| tmp_config_obj.set_gpu_mode(kGpuModeGfxStream); |
| } |
| } else { |
| LOG(INFO) << "GPU auto mode: did not detect prerequisites for " |
| "accelerated rendering support, enabling " |
| "--gpu_mode=guest_swiftshader."; |
| tmp_config_obj.set_gpu_mode(kGpuModeGuestSwiftshader); |
| } |
| } else if (tmp_config_obj.gpu_mode() == kGpuModeGfxStream || |
| tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) { |
| if (!ShouldEnableAcceleratedRendering(graphics_availability)) { |
| LOG(ERROR) << "--gpu_mode=" |
| << tmp_config_obj.gpu_mode() |
| << " was requested but the prerequisites for accelerated " |
| "rendering were not detected so the device may not " |
| "function correctly. Please consider switching to " |
| "--gpu_mode=auto or --gpu_mode=guest_swiftshader."; |
| } |
| } |
| |
| tmp_config_obj.set_restart_subprocesses(FLAGS_restart_subprocesses); |
| tmp_config_obj.set_gpu_capture_binary(FLAGS_gpu_capture_binary); |
| if (!tmp_config_obj.gpu_capture_binary().empty()) { |
| CHECK(tmp_config_obj.gpu_mode() == kGpuModeGfxStream) |
| << "GPU capture only supported with --gpu_mode=gfxstream"; |
| |
| // GPU capture runs in a detached mode where the "launcher" process |
| // intentionally exits immediately. |
| CHECK(!tmp_config_obj.restart_subprocesses()) |
| << "GPU capture only supported with --norestart_subprocesses"; |
| } |
| |
| tmp_config_obj.set_hwcomposer(FLAGS_hwcomposer); |
| if (!tmp_config_obj.hwcomposer().empty()) { |
| if (tmp_config_obj.hwcomposer() == kHwComposerRanchu) { |
| CHECK(tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl) |
| << "ranchu hwcomposer not supported with --gpu_mode=drm_virgl"; |
| } |
| } |
| |
| if (tmp_config_obj.hwcomposer() == kHwComposerAuto) { |
| if (tmp_config_obj.gpu_mode() == kGpuModeDrmVirgl) { |
| tmp_config_obj.set_hwcomposer(kHwComposerDrm); |
| } else { |
| tmp_config_obj.set_hwcomposer(kHwComposerRanchu); |
| } |
| } |
| |
| // The device needs to avoid having both hwcomposer2.4 and hwcomposer3 |
| // services running at the same time so warn the user to manually build |
| // in drm_hwcomposer when needed. |
| if (tmp_config_obj.hwcomposer() == kHwComposerAuto) { |
| LOG(WARNING) << "In order to run with --hwcomposer=drm. Please make sure " |
| "Cuttlefish was built with " |
| "TARGET_ENABLE_DRMHWCOMPOSER=true."; |
| } |
| |
| tmp_config_obj.set_enable_gpu_udmabuf(FLAGS_enable_gpu_udmabuf); |
| tmp_config_obj.set_enable_gpu_angle(FLAGS_enable_gpu_angle); |
| |
| // Sepolicy rules need to be updated to support gpu mode. Temporarily disable |
| // auto-enabling sandbox when gpu is enabled (b/152323505). |
| if (tmp_config_obj.gpu_mode() != kGpuModeGuestSwiftshader) { |
| SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT); |
| } |
| |
| if (vmm->ConfigureGraphics(tmp_config_obj).empty()) { |
| LOG(FATAL) << "Invalid (gpu_mode=," << FLAGS_gpu_mode << |
| " hwcomposer= " << FLAGS_hwcomposer << |
| ") does not work with vm_manager=" << FLAGS_vm_manager; |
| } |
| |
| CHECK(!FLAGS_smt || FLAGS_cpus % 2 == 0) |
| << "CPUs must be a multiple of 2 in SMT mode"; |
| tmp_config_obj.set_cpus(FLAGS_cpus); |
| tmp_config_obj.set_smt(FLAGS_smt); |
| |
| tmp_config_obj.set_memory_mb(FLAGS_memory_mb); |
| |
| tmp_config_obj.set_setupwizard_mode(FLAGS_setupwizard_mode); |
| |
| auto secure_hals = android::base::Split(FLAGS_secure_hals, ","); |
| tmp_config_obj.set_secure_hals( |
| std::set<std::string>(secure_hals.begin(), secure_hals.end())); |
| |
| tmp_config_obj.set_gdb_port(FLAGS_gdb_port); |
| |
| tmp_config_obj.set_guest_enforce_security(FLAGS_guest_enforce_security); |
| tmp_config_obj.set_extra_kernel_cmdline(FLAGS_extra_kernel_cmdline); |
| tmp_config_obj.set_extra_bootconfig_args(FLAGS_extra_bootconfig_args); |
| |
| if (FLAGS_console) { |
| SetCommandLineOptionWithMode("enable_sandbox", "false", SET_FLAGS_DEFAULT); |
| } |
| |
| tmp_config_obj.set_console(FLAGS_console); |
| tmp_config_obj.set_kgdb(FLAGS_console && FLAGS_kgdb); |
| |
| tmp_config_obj.set_host_tools_version(HostToolsCrc()); |
| |
| tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed); |
| |
| tmp_config_obj.set_qemu_binary_dir(FLAGS_qemu_binary_dir); |
| tmp_config_obj.set_crosvm_binary(FLAGS_crosvm_binary); |
| tmp_config_obj.set_gem5_binary_dir(FLAGS_gem5_binary_dir); |
| |
| tmp_config_obj.set_seccomp_policy_dir(FLAGS_seccomp_policy_dir); |
| |
| tmp_config_obj.set_enable_webrtc(FLAGS_start_webrtc); |
| tmp_config_obj.set_webrtc_assets_dir(FLAGS_webrtc_assets_dir); |
| tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir); |
| tmp_config_obj.set_sig_server_secure(FLAGS_webrtc_sig_server_secure); |
| // Note: This will be overridden if the sig server is started by us |
| tmp_config_obj.set_sig_server_port(FLAGS_webrtc_sig_server_port); |
| tmp_config_obj.set_sig_server_address(FLAGS_webrtc_sig_server_addr); |
| tmp_config_obj.set_sig_server_path(FLAGS_webrtc_sig_server_path); |
| tmp_config_obj.set_sig_server_strict(FLAGS_verify_sig_server_certificate); |
| tmp_config_obj.set_sig_server_headers_path(FLAGS_sig_server_headers_file); |
| |
| auto tcp_range = ParsePortRange(FLAGS_tcp_port_range); |
| tmp_config_obj.set_webrtc_tcp_port_range(tcp_range); |
| auto udp_range = ParsePortRange(FLAGS_udp_port_range); |
| tmp_config_obj.set_webrtc_udp_port_range(udp_range); |
| |
| tmp_config_obj.set_enable_modem_simulator(FLAGS_enable_modem_simulator && |
| !FLAGS_enable_minimal_mode); |
| tmp_config_obj.set_modem_simulator_instance_number(modem_simulator_count); |
| tmp_config_obj.set_modem_simulator_sim_type(FLAGS_modem_simulator_sim_type); |
| |
| tmp_config_obj.set_webrtc_enable_adb_websocket( |
| FLAGS_webrtc_enable_adb_websocket); |
| |
| tmp_config_obj.set_run_as_daemon(FLAGS_daemon); |
| |
| tmp_config_obj.set_data_policy(FLAGS_data_policy); |
| tmp_config_obj.set_blank_data_image_mb(FLAGS_blank_data_image_mb); |
| |
| tmp_config_obj.set_enable_gnss_grpc_proxy(FLAGS_start_gnss_proxy); |
| |
| tmp_config_obj.set_enable_vehicle_hal_grpc_server( |
| FLAGS_enable_vehicle_hal_grpc_server); |
| |
| tmp_config_obj.set_bootloader(FLAGS_bootloader); |
| |
| tmp_config_obj.set_enable_metrics(FLAGS_report_anonymous_usage_stats); |
| |
| if (!FLAGS_boot_slot.empty()) { |
| tmp_config_obj.set_boot_slot(FLAGS_boot_slot); |
| } |
| |
| tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath()); |
| |
| tmp_config_obj.set_ril_dns(FLAGS_ril_dns); |
| |
| tmp_config_obj.set_enable_minimal_mode(FLAGS_enable_minimal_mode); |
| |
| tmp_config_obj.set_vhost_net(FLAGS_vhost_net); |
| |
| tmp_config_obj.set_vhost_user_mac80211_hwsim(FLAGS_vhost_user_mac80211_hwsim); |
| |
| if ((FLAGS_ap_rootfs_image.empty()) != (FLAGS_ap_kernel_image.empty())) { |
| LOG(FATAL) << "Either both ap_rootfs_image and ap_kernel_image should be " |
| "set or neither should be set."; |
| } |
| |
| tmp_config_obj.set_ap_rootfs_image(FLAGS_ap_rootfs_image); |
| tmp_config_obj.set_ap_kernel_image(FLAGS_ap_kernel_image); |
| |
| tmp_config_obj.set_wmediumd_config(FLAGS_wmediumd_config); |
| |
| tmp_config_obj.set_rootcanal_hci_port(7300); |
| tmp_config_obj.set_rootcanal_link_port(7400); |
| tmp_config_obj.set_rootcanal_test_port(7500); |
| tmp_config_obj.set_rootcanal_config_file( |
| FLAGS_bluetooth_controller_properties_file); |
| tmp_config_obj.set_rootcanal_default_commands_file( |
| FLAGS_bluetooth_default_commands_file); |
| |
| tmp_config_obj.set_record_screen(FLAGS_record_screen); |
| |
| tmp_config_obj.set_enable_host_bluetooth(FLAGS_enable_host_bluetooth); |
| |
| tmp_config_obj.set_protected_vm(FLAGS_protected_vm); |
| |
| tmp_config_obj.set_userdata_format(FLAGS_userdata_format); |
| |
| std::vector<int> num_instances; |
| for (int i = 0; i < FLAGS_num_instances; i++) { |
| num_instances.push_back(GetInstance() + i); |
| } |
| std::vector<std::string> gnss_file_paths = android::base::Split(FLAGS_gnss_file_path, ","); |
| |
| bool is_first_instance = true; |
| for (const auto& num : num_instances) { |
| IfaceConfig iface_config; |
| if (FLAGS_use_allocd) { |
| auto iface_opt = AllocateNetworkInterfaces(); |
| if (!iface_opt.has_value()) { |
| LOG(FATAL) << "Failed to acquire network interfaces"; |
| } |
| iface_config = iface_opt.value(); |
| } else { |
| iface_config = DefaultNetworkInterfaces(num); |
| } |
| |
| auto instance = tmp_config_obj.ForInstance(num); |
| auto const_instance = |
| const_cast<const CuttlefishConfig&>(tmp_config_obj).ForInstance(num); |
| instance.set_use_allocd(FLAGS_use_allocd); |
| if (FLAGS_use_random_serial) { |
| instance.set_serial_number( |
| RandomSerialNumber("CFCVD" + std::to_string(num))); |
| } else { |
| instance.set_serial_number(FLAGS_serial_number + std::to_string(num)); |
| } |
| // call this before all stuff that has vsock server: e.g. touchpad, keyboard, etc |
| const auto vsock_guest_cid = FLAGS_vsock_guest_cid + num - GetInstance(); |
| instance.set_vsock_guest_cid(vsock_guest_cid); |
| auto calc_vsock_port = [vsock_guest_cid](const int base_port) { |
| // a base (vsock) port is like 9200 for modem_simulator, etc |
| return cuttlefish::GetVsockServerPort(base_port, vsock_guest_cid); |
| }; |
| instance.set_session_id(iface_config.mobile_tap.session_id); |
| |
| instance.set_mobile_bridge_name(StrForInstance("cvd-mbr-", num)); |
| instance.set_mobile_tap_name(iface_config.mobile_tap.name); |
| instance.set_wifi_tap_name(iface_config.wireless_tap.name); |
| instance.set_ethernet_tap_name(iface_config.ethernet_tap.name); |
| |
| instance.set_uuid(FLAGS_uuid); |
| |
| instance.set_modem_simulator_host_id(1000 + num); // Must be 4 digits |
| // the deprecated vnc was 6444 + num - 1, and qemu_vnc was vnc - 5900 |
| instance.set_qemu_vnc_server_port(544 + num - 1); |
| instance.set_adb_host_port(6520 + num - 1); |
| instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1)); |
| instance.set_confui_host_vsock_port(7700 + num - 1); |
| instance.set_tombstone_receiver_port(calc_vsock_port(6600)); |
| instance.set_vehicle_hal_server_port(9300 + num - 1); |
| instance.set_audiocontrol_server_port(9410); /* OK to use the same port number across instances */ |
| instance.set_config_server_port(calc_vsock_port(6800)); |
| |
| if (tmp_config_obj.gpu_mode() != kGpuModeDrmVirgl && |
| tmp_config_obj.gpu_mode() != kGpuModeGfxStream) { |
| if (FLAGS_vm_manager == QemuManager::name()) { |
| instance.set_keyboard_server_port(calc_vsock_port(7000)); |
| instance.set_touch_server_port(calc_vsock_port(7100)); |
| } |
| } |
| |
| instance.set_gnss_grpc_proxy_server_port(7200 + num -1); |
| |
| if (num <= gnss_file_paths.size()) { |
| instance.set_gnss_file_path(gnss_file_paths[num-1]); |
| } |
| |
| instance.set_camera_server_port(FLAGS_camera_server_port); |
| |
| if (FLAGS_protected_vm) { |
| instance.set_virtual_disk_paths( |
| {const_instance.PerInstancePath("os_composite.img")}); |
| } else { |
| std::vector<std::string> virtual_disk_paths = { |
| const_instance.PerInstancePath("persistent_composite.img"), |
| }; |
| if (FLAGS_vm_manager != Gem5Manager::name()) { |
| virtual_disk_paths.insert(virtual_disk_paths.begin(), |
| const_instance.PerInstancePath("overlay.img")); |
| } else { |
| // Gem5 already uses CoW wrappers around disk images |
| virtual_disk_paths.insert(virtual_disk_paths.begin(), |
| tmp_config_obj.os_composite_disk_path()); |
| } |
| if (FLAGS_use_sdcard) { |
| virtual_disk_paths.push_back(const_instance.sdcard_path()); |
| } |
| instance.set_virtual_disk_paths(virtual_disk_paths); |
| } |
| |
| // We'd like to set mac prefix to be 5554, 5555, 5556, ... in normal cases. |
| // When --base_instance_num=3, this might be 5556, 5557, 5558, ... (skipping |
| // first two) |
| instance.set_wifi_mac_prefix(5554 + (num - 1)); |
| |
| instance.set_start_webrtc_signaling_server(false); |
| |
| if (FLAGS_webrtc_device_id.empty()) { |
| // Use the instance's name as a default |
| instance.set_webrtc_device_id(const_instance.instance_name()); |
| } else { |
| std::string device_id = FLAGS_webrtc_device_id; |
| size_t pos; |
| while ((pos = device_id.find("{num}")) != std::string::npos) { |
| device_id.replace(pos, strlen("{num}"), std::to_string(num)); |
| } |
| instance.set_webrtc_device_id(device_id); |
| } |
| if (!is_first_instance || !FLAGS_start_webrtc) { |
| // Only the first instance starts the signaling server or proxy |
| instance.set_start_webrtc_signaling_server(false); |
| instance.set_start_webrtc_sig_server_proxy(false); |
| } else { |
| auto port = 8443 + num - 1; |
| // Change the signaling server port for all instances |
| tmp_config_obj.set_sig_server_port(port); |
| // Either the signaling server or the proxy is started, never both |
| instance.set_start_webrtc_signaling_server(FLAGS_start_webrtc_sig_server); |
| // The proxy is only started if the host operator is available |
| instance.set_start_webrtc_sig_server_proxy( |
| cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH) && |
| !FLAGS_start_webrtc_sig_server); |
| } |
| |
| // Start wmediumd process for the first instance if |
| // vhost_user_mac80211_hwsim is not specified. |
| const bool start_wmediumd = |
| FLAGS_vhost_user_mac80211_hwsim.empty() && is_first_instance; |
| if (start_wmediumd) { |
| // TODO(b/199020470) move this to the directory for shared resources |
| auto vhost_user_socket_path = |
| const_instance.PerInstanceInternalPath("vhost_user_mac80211"); |
| auto wmediumd_api_socket_path = |
| const_instance.PerInstanceInternalPath("wmediumd_api_server"); |
| |
| tmp_config_obj.set_vhost_user_mac80211_hwsim(vhost_user_socket_path); |
| tmp_config_obj.set_wmediumd_api_server_socket(wmediumd_api_socket_path); |
| instance.set_start_wmediumd(true); |
| } else { |
| instance.set_start_wmediumd(false); |
| } |
| |
| instance.set_start_rootcanal(is_first_instance); |
| |
| instance.set_start_ap(!FLAGS_ap_rootfs_image.empty() && |
| !FLAGS_ap_kernel_image.empty() && is_first_instance); |
| |
| is_first_instance = false; |
| |
| // instance.modem_simulator_ports := "" or "[port,]*port" |
| if (modem_simulator_count > 0) { |
| std::stringstream modem_ports; |
| for (auto index {0}; index < modem_simulator_count - 1; index++) { |
| auto port = 9200 + (modem_simulator_count * (num - 1)) + index; |
| modem_ports << calc_vsock_port(port) << ","; |
| } |
| auto port = 9200 + (modem_simulator_count * (num - 1)) + |
| modem_simulator_count - 1; |
| modem_ports << calc_vsock_port(port); |
| instance.set_modem_simulator_ports(modem_ports.str()); |
| } else { |
| instance.set_modem_simulator_ports(""); |
| } |
| } // end of num_instances loop |
| |
| std::vector<std::string> names; |
| for (const auto& instance : tmp_config_obj.Instances()) { |
| names.emplace_back(instance.instance_name()); |
| } |
| tmp_config_obj.set_instance_names(names); |
| |
| tmp_config_obj.set_enable_sandbox(FLAGS_enable_sandbox); |
| |
| // Audio is not available for Arm64 |
| SetCommandLineOptionWithMode( |
| "enable_audio", |
| (cuttlefish::HostArch() == cuttlefish::Arch::Arm64) ? "false" : "true", |
| SET_FLAGS_DEFAULT); |
| tmp_config_obj.set_enable_audio(FLAGS_enable_audio); |
| |
| return tmp_config_obj; |
| } |
| |
| void SetDefaultFlagsForQemu(Arch target_arch) { |
| // for now, we don't set non-default options for QEMU |
| if (FLAGS_gpu_mode == kGpuModeGuestSwiftshader && !FLAGS_start_webrtc) { |
| // This makes WebRTC the default streamer unless the user requests |
| // another via a --star_<streamer> flag, while at the same time it's |
| // possible to run without any streamer by setting --start_webrtc=false. |
| SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT); |
| } |
| std::string default_bootloader = |
| DefaultHostArtifactsPath("etc/bootloader_"); |
| if(target_arch == Arch::Arm) { |
| // Bootloader is unstable >512MB RAM on 32-bit ARM |
| SetCommandLineOptionWithMode("memory_mb", "512", SET_FLAGS_VALUE); |
| default_bootloader += "arm"; |
| } else if (target_arch == Arch::Arm64) { |
| default_bootloader += "aarch64"; |
| } else { |
| default_bootloader += "x86_64"; |
| } |
| default_bootloader += "/bootloader.qemu"; |
| SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(), |
| SET_FLAGS_DEFAULT); |
| } |
| |
| void SetDefaultFlagsForCrosvm() { |
| if (!FLAGS_start_webrtc) { |
| // This makes WebRTC the default streamer unless the user requests |
| // another via a --star_<streamer> flag, while at the same time it's |
| // possible to run without any streamer by setting --start_webrtc=false. |
| SetCommandLineOptionWithMode("start_webrtc", "true", SET_FLAGS_DEFAULT); |
| } |
| |
| std::set<Arch> supported_archs{Arch::X86_64}; |
| bool default_enable_sandbox = |
| supported_archs.find(HostArch()) != supported_archs.end() && |
| EnsureDirectoryExists(kCrosvmVarEmptyDir).ok() && |
| IsDirectoryEmpty(kCrosvmVarEmptyDir) && !IsRunningInContainer(); |
| SetCommandLineOptionWithMode("enable_sandbox", |
| (default_enable_sandbox ? "true" : "false"), |
| SET_FLAGS_DEFAULT); |
| |
| std::string default_bootloader = FLAGS_system_image_dir + "/bootloader"; |
| SetCommandLineOptionWithMode("bootloader", default_bootloader.c_str(), |
| SET_FLAGS_DEFAULT); |
| } |
| |
| void SetDefaultFlagsForGem5() { |
| // TODO: Add support for gem5 gpu models |
| SetCommandLineOptionWithMode("gpu_mode", kGpuModeGuestSwiftshader, |
| SET_FLAGS_DEFAULT); |
| |
| SetCommandLineOptionWithMode("cpus", "1", SET_FLAGS_DEFAULT); |
| } |
| |
| Result<KernelConfig> GetKernelConfigAndSetDefaults() { |
| CF_EXPECT(ResolveInstanceFiles(), "Failed to resolve instance files"); |
| |
| KernelConfig kernel_config = CF_EXPECT(ReadKernelConfig()); |
| |
| if (FLAGS_vm_manager == "") { |
| if (IsHostCompatible(kernel_config.target_arch)) { |
| FLAGS_vm_manager = CrosvmManager::name(); |
| } else { |
| FLAGS_vm_manager = QemuManager::name(); |
| } |
| } |
| |
| if (FLAGS_vm_manager == QemuManager::name()) { |
| SetDefaultFlagsForQemu(kernel_config.target_arch); |
| } else if (FLAGS_vm_manager == CrosvmManager::name()) { |
| SetDefaultFlagsForCrosvm(); |
| } else if (FLAGS_vm_manager == Gem5Manager::name()) { |
| // TODO: Get the other architectures working |
| if (kernel_config.target_arch != Arch::Arm64) { |
| return CF_ERR("Gem5 only supports ARM64"); |
| } |
| SetDefaultFlagsForGem5(); |
| } else { |
| return CF_ERR("Unknown Virtual Machine Manager: " << FLAGS_vm_manager); |
| } |
| if (FLAGS_vm_manager != Gem5Manager::name()) { |
| auto host_operator_present = |
| cuttlefish::FileIsSocket(HOST_OPERATOR_SOCKET_PATH); |
| // The default for starting signaling server depends on whether or not webrtc |
| // is to be started and the presence of the host orchestrator. |
| SetCommandLineOptionWithMode( |
| "start_webrtc_sig_server", |
| FLAGS_start_webrtc && !host_operator_present ? "true" : "false", |
| SET_FLAGS_DEFAULT); |
| SetCommandLineOptionWithMode( |
| "webrtc_sig_server_addr", |
| host_operator_present ? HOST_OPERATOR_SOCKET_PATH : "0.0.0.0", |
| SET_FLAGS_DEFAULT); |
| } |
| // Set the env variable to empty (in case the caller passed a value for it). |
| unsetenv(kCuttlefishConfigEnvVarName); |
| |
| return kernel_config; |
| } |
| |
| std::string GetConfigFilePath(const CuttlefishConfig& config) { |
| return config.AssemblyPath("cuttlefish_config.json"); |
| } |
| |
| std::string GetCuttlefishEnvPath() { |
| return StringFromEnv("HOME", ".") + "/.cuttlefish.sh"; |
| } |
| |
| } // namespace cuttlefish |