diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-04-25 18:02:51 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-04-25 18:02:51 +0000 |
commit | f868842436a3bb534ffbc2cbe9159064a80df710 (patch) | |
tree | e35d46772a21dff5a171cca6ec039b0fc9f77afb | |
parent | 2ea70bc57ef228f9975250839d1eb2a603725bd8 (diff) | |
parent | eef6290c3da817cc9b8b72bbcfb1bfc6d4e975b6 (diff) | |
download | cuttlefish-emu-35-1-release.tar.gz |
Snap for 11762816 from eef6290c3da817cc9b8b72bbcfb1bfc6d4e975b6 to emu-35-1-releaseemu-35-1-release
Change-Id: Ia9996f1eab145ded9cfcaf25ab6333ce95e8cfad
45 files changed, 1018 insertions, 599 deletions
diff --git a/build/Android.bp b/build/Android.bp index 33563de5a..1e69ce018 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -45,6 +45,33 @@ soong_config_module_type { ], } +// Start of generated qemu_aarch64_linux_gnu_binary +// Generated by gen_android_bp.py +qemu_aarch64_linux_gnu_binary = [ + "aarch64_linux_gnu_libc++.so.1_binary_for_qemu", + "aarch64_linux_gnu_libc++abi.so.1_binary_for_qemu", + "aarch64_linux_gnu_libepoxy.so.0_binary_for_qemu", + "aarch64_linux_gnu_libgbm.so.1_binary_for_qemu", + "aarch64_linux_gnu_libgfxstream_backend.so.0_binary_for_qemu", + "aarch64_linux_gnu_librutabaga_gfx_ffi.so.0_binary_for_qemu", + "aarch64_linux_gnu_libunwind.so.1_binary_for_qemu", + "aarch64_linux_gnu_libvirglrenderer.so.1_binary_for_qemu", + "aarch64_linux_gnu_libz.so.1_binary_for_qemu", + "aarch64_linux_gnu_qemu-system-aarch64_binary_for_qemu", + "aarch64_linux_gnu_qemu-system-riscv64_binary_for_qemu", + "aarch64_linux_gnu_qemu-system-x86_64_binary_for_qemu", +] +// End of generated qemu_aarch64_linux_gnu_binary + +// Start of generated qemu_aarch64_linux_gnu_resource +// Generated by gen_android_bp.py +qemu_aarch64_linux_gnu_resource = [ + "aarch64_efi-virtio.rom_resource_for_qemu", + "aarch64_en-us_resource_for_qemu", + "aarch64_opensbi-riscv64-generic-fw_dynamic.bin_resource_for_qemu", +] +// End of generated qemu_aarch64_linux_gnu_resource + // Start of generated qemu_x86_64_linux_gnu_binary // Generated by gen_android_bp.py qemu_x86_64_linux_gnu_binary = [ @@ -247,7 +274,7 @@ cvd_host_aarch64_crosvm = [ "aarch64_linux_gnu_libwayland_client.so.0_for_crosvm", ] -cvd_host_aarch64 = cvd_host_aarch64_crosvm + cvd_host_aarch64_graphics_detector +cvd_host_aarch64 = cvd_host_aarch64_crosvm + cvd_host_aarch64_graphics_detector + qemu_aarch64_linux_gnu_binary cvd_host_seccomp_policy_x86_64 = [ "9p_device.policy_x86_64", @@ -428,7 +455,7 @@ cvd_host_package_customization { deps: cvd_host_aarch64, multilib: { common: { - deps: cvd_host_seccomp_policy_aarch64, + deps: cvd_host_seccomp_policy_aarch64 + qemu_aarch64_linux_gnu_resource, }, }, }, diff --git a/common/libs/utils/files.cpp b/common/libs/utils/files.cpp index 5fa1e6ecf..0f9f93ec1 100644 --- a/common/libs/utils/files.cpp +++ b/common/libs/utils/files.cpp @@ -52,6 +52,7 @@ #include <numeric> #include <ostream> #include <ratio> +#include <regex> #include <string> #include <vector> @@ -663,6 +664,57 @@ Result<void> WaitForUnixSocket(const std::string& path, int timeoutSec) { return CF_ERR("This shouldn't be executed"); } + +Result<void> WaitForUnixSocketListeningWithoutConnect(const std::string& path, + int timeoutSec) { + const auto targetTime = + std::chrono::system_clock::now() + std::chrono::seconds(timeoutSec); + + CF_EXPECT(WaitForFile(path, timeoutSec), + "Waiting for socket path creation failed"); + CF_EXPECT(FileIsSocket(path), "Specified path is not a socket"); + + std::regex socket_state_regex("TST=(.*)"); + + while (true) { + const auto currentTime = std::chrono::system_clock::now(); + + if (currentTime >= targetTime) { + return CF_ERR("Timed out"); + } + + Command lsof("lsof"); + lsof.AddParameter(/*"format"*/ "-F", /*"connection state"*/ "TST"); + lsof.AddParameter(path); + std::string lsof_out; + std::string lsof_err; + int rval = + RunWithManagedStdio(std::move(lsof), nullptr, &lsof_out, &lsof_err); + if (rval != 0) { + return CF_ERR("Failed to run `lsof`, stderr: " << lsof_err); + } + + LOG(DEBUG) << "lsof stdout:" << lsof_out; + + std::smatch socket_state_match; + if (!std::regex_search(lsof_out, socket_state_match, socket_state_regex)) { + return CF_ERR("Failed to find state in `lsof` stdout: " << lsof_out); + } + if (socket_state_match.size() != 2) { + return CF_ERR( + "Unexpected number of matches in `lsof` stdout: " << lsof_out); + } + + const std::string& socket_state = socket_state_match[1]; + if (socket_state == "LISTEN") { + return {}; + } + + sched_yield(); + } + + return CF_ERR("This shouldn't be executed"); +} #endif namespace { diff --git a/common/libs/utils/files.h b/common/libs/utils/files.h index cf13dea72..6e423cda4 100644 --- a/common/libs/utils/files.h +++ b/common/libs/utils/files.h @@ -84,6 +84,8 @@ Result<void> WalkDirectory( #ifdef __linux__ Result<void> WaitForFile(const std::string& path, int timeoutSec); Result<void> WaitForUnixSocket(const std::string& path, int timeoutSec); +Result<void> WaitForUnixSocketListeningWithoutConnect(const std::string& path, + int timeoutSec); #endif // parameter to EmulateAbsolutePath diff --git a/common/libs/utils/subprocess.cpp b/common/libs/utils/subprocess.cpp index 6595cd5ed..40b13c3cf 100644 --- a/common/libs/utils/subprocess.cpp +++ b/common/libs/utils/subprocess.cpp @@ -293,6 +293,23 @@ StopperResult KillSubprocess(Subprocess* subprocess) { return StopperResult::kStopSuccess; } +SubprocessStopper KillSubprocessFallback(std::function<StopperResult()> nice) { + return KillSubprocessFallback([nice](Subprocess*) { return nice(); }); +} + +SubprocessStopper KillSubprocessFallback(SubprocessStopper nice_stopper) { + return [nice_stopper](Subprocess* proccess) { + auto nice_result = nice_stopper(proccess); + if (nice_result == StopperResult::kStopFailure) { + auto harsh_result = KillSubprocess(proccess); + return harsh_result == StopperResult::kStopSuccess + ? StopperResult::kStopCrash + : harsh_result; + } + return nice_result; + }; +} + Command::Command(std::string executable, SubprocessStopper stopper) : subprocess_stopper_(stopper) { for (char** env = environ; *env; env++) { diff --git a/common/libs/utils/subprocess.h b/common/libs/utils/subprocess.h index 2f695304d..4fadd757e 100644 --- a/common/libs/utils/subprocess.h +++ b/common/libs/utils/subprocess.h @@ -56,6 +56,10 @@ class Subprocess; using SubprocessStopper = std::function<StopperResult(Subprocess*)>; // Kills a process by sending it the SIGKILL signal. StopperResult KillSubprocess(Subprocess* subprocess); +/* Creates a `SubprocessStopper` that first tries `nice_stopper` then falls back + * to `KillSubprocess` if that fails. */ +SubprocessStopper KillSubprocessFallback(std::function<StopperResult()>); +SubprocessStopper KillSubprocessFallback(SubprocessStopper nice_stopper); // Keeps track of a running (sub)process. Allows to wait for its completion. // It's an error to wait twice for the same subprocess. diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc index 5ad253b71..37d931af0 100644 --- a/host/commands/assemble_cvd/assemble_cvd.cc +++ b/host/commands/assemble_cvd/assemble_cvd.cc @@ -223,6 +223,7 @@ Result<std::set<std::string>> PreservingOnResume( preserving.insert("os_composite_gpt_header.img"); preserving.insert("os_composite_gpt_footer.img"); preserving.insert("os_composite.img"); + preserving.insert("os_vbmeta.img"); preserving.insert("sdcard.img"); preserving.insert("sdcard_overlay.img"); preserving.insert("boot_repacked.img"); @@ -245,7 +246,7 @@ Result<std::set<std::string>> PreservingOnResume( preserving.insert("factory_reset_protected.img"); preserving.insert("misc.img"); preserving.insert("metadata.img"); - preserving.insert("vbmeta.img"); + preserving.insert("persistent_vbmeta.img"); preserving.insert("oemlock_secure"); preserving.insert("oemlock_insecure"); // Preserve logs if restoring from a snapshot. diff --git a/host/commands/assemble_cvd/boot_config.cc b/host/commands/assemble_cvd/boot_config.cc index 35ccfbb9b..e24f074ac 100644 --- a/host/commands/assemble_cvd/boot_config.cc +++ b/host/commands/assemble_cvd/boot_config.cc @@ -32,9 +32,9 @@ #include "common/libs/utils/size_utils.h" #include "common/libs/utils/subprocess.h" #include "host/commands/assemble_cvd/bootconfig_args.h" +#include "host/libs/avb/avb.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/kernel_args.h" -#include "host/libs/config/known_paths.h" #include "host/libs/vm_manager/crosvm_manager.h" #include "host/libs/vm_manager/vm_manager.h" @@ -42,9 +42,6 @@ using cuttlefish::vm_manager::CrosvmManager; DECLARE_string(vm_manager); -// Taken from external/avb/avbtool.py; this define is not in the headers -#define MAX_AVB_METADATA_SIZE 69632ul - namespace cuttlefish { namespace { @@ -200,24 +197,11 @@ Result<void> PrepareBootEnvImage( "Unable to run mkenvimage_slim. Exited with status {}", success); const off_t boot_env_size_bytes = - AlignToPowerOf2(MAX_AVB_METADATA_SIZE + 4096, PARTITION_SIZE_SHIFT); - - auto avbtool_path = HostBinaryPath("avbtool"); - Command boot_env_hash_footer_cmd(avbtool_path); - boot_env_hash_footer_cmd.AddParameter("add_hash_footer"); - boot_env_hash_footer_cmd.AddParameter("--image"); - boot_env_hash_footer_cmd.AddParameter(tmp_boot_env_image_path); - boot_env_hash_footer_cmd.AddParameter("--partition_size"); - boot_env_hash_footer_cmd.AddParameter(boot_env_size_bytes); - boot_env_hash_footer_cmd.AddParameter("--partition_name"); - boot_env_hash_footer_cmd.AddParameter("uboot_env"); - boot_env_hash_footer_cmd.AddParameter("--key"); - boot_env_hash_footer_cmd.AddParameter(TestKeyRsa4096()); - boot_env_hash_footer_cmd.AddParameter("--algorithm"); - boot_env_hash_footer_cmd.AddParameter("SHA256_RSA4096"); - success = boot_env_hash_footer_cmd.Start().Wait(); - CF_EXPECTF(success == 0, - "Unable to append hash footer. Exited with status {}", success); + AlignToPowerOf2(kMaxAvbMetadataSize + 4096, PARTITION_SIZE_SHIFT); + + std::unique_ptr<Avb> avbtool = GetDefaultAvb(); + CF_EXPECT(avbtool->AddHashFooter(tmp_boot_env_image_path, "uboot_env", + boot_env_size_bytes)); if (!FileExists(image_path) || ReadFile(image_path) != ReadFile(tmp_boot_env_image_path)) { diff --git a/host/commands/assemble_cvd/boot_image_utils.cc b/host/commands/assemble_cvd/boot_image_utils.cc index a601e5e93..1fbeef543 100644 --- a/host/commands/assemble_cvd/boot_image_utils.cc +++ b/host/commands/assemble_cvd/boot_image_utils.cc @@ -15,22 +15,26 @@ */ #include "host/commands/assemble_cvd/boot_image_utils.h" -#include "common/libs/fs/shared_fd.h" -#include "host/libs/config/cuttlefish_config.h" #include <string.h> #include <unistd.h> #include <fstream> +#include <memory> #include <regex> #include <sstream> +#include <string> #include <android-base/logging.h> #include <android-base/strings.h> +#include "common/libs/fs/shared_fd.h" #include "common/libs/utils/files.h" #include "common/libs/utils/result.h" #include "common/libs/utils/subprocess.h" +#include "host/libs/avb/avb.cpp" +#include "host/libs/config/cuttlefish_config.h" +#include "host/libs/config/known_paths.h" const char TMP_EXTENSION[] = ".tmp"; const char CPIO_EXT[] = ".cpio"; @@ -158,26 +162,13 @@ void UnpackRamdisk(const std::string& original_ramdisk_path, << success; } -bool GetAvbMetadatFromBootImage(const std::string& boot_image_path, - const std::string& unpack_dir) { - auto avbtool_path = HostBinaryPath("avbtool"); - Command avb_cmd(avbtool_path); - avb_cmd.AddParameter("info_image"); - avb_cmd.AddParameter("--image"); - avb_cmd.AddParameter(boot_image_path); - - auto output_file = SharedFD::Creat(unpack_dir + "/boot_params", 0666); - if (!output_file->IsOpen()) { - LOG(ERROR) << "Unable to create intermediate boot params file: " - << output_file->StrError(); - return false; - } - avb_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, output_file); - - int success = avb_cmd.Start().Wait(); - - if (success != 0) { - LOG(ERROR) << "Unable to run avb command. Exited with status " << success; +bool GetAvbMetadataFromBootImage(const std::string& boot_image_path, + const std::string& unpack_dir) { + std::unique_ptr<Avb> avbtool = GetDefaultAvb(); + Result<void> result = + avbtool->WriteInfoImage(boot_image_path, unpack_dir + "/boot_params"); + if (!result.ok()) { + LOG(ERROR) << result.error().Trace(); return false; } return true; @@ -355,18 +346,12 @@ bool RepackVendorBootImage(const std::string& new_ramdisk, return false; } - auto avbtool_path = HostBinaryPath("avbtool"); - Command avb_cmd(avbtool_path); - avb_cmd.AddParameter("add_hash_footer"); - avb_cmd.AddParameter("--image"); - avb_cmd.AddParameter(tmp_vendor_boot_image_path); - avb_cmd.AddParameter("--partition_size"); - avb_cmd.AddParameter(FileSize(vendor_boot_image_path)); - avb_cmd.AddParameter("--partition_name"); - avb_cmd.AddParameter("vendor_boot"); - success = avb_cmd.Start().Wait(); - if (success != 0) { - LOG(ERROR) << "Unable to run avbtool. Exited with status " << success; + auto avbtool = Avb(AvbToolBinary()); + Result<void> result = + avbtool.AddHashFooter(tmp_vendor_boot_image_path, "vendor_boot", + FileSize(vendor_boot_image_path)); + if (!result.ok()) { + LOG(ERROR) << result.error().Trace(); return false; } @@ -468,7 +453,7 @@ Result<std::string> ReadAndroidVersionFromBootImage( if (!unpack_dir) { return CF_ERR("boot image unpack dir could not be created"); } - bool unpack_status = GetAvbMetadatFromBootImage(boot_image_path, unpack_dir); + bool unpack_status = GetAvbMetadataFromBootImage(boot_image_path, unpack_dir); if (!unpack_status) { RecursivelyRemoveDirectory(unpack_dir); return CF_ERR("\"" + boot_image_path + "\" boot image unpack into \"" + diff --git a/host/commands/assemble_cvd/boot_image_utils.h b/host/commands/assemble_cvd/boot_image_utils.h index 657e6f75d..26a3dc38c 100644 --- a/host/commands/assemble_cvd/boot_image_utils.h +++ b/host/commands/assemble_cvd/boot_image_utils.h @@ -23,10 +23,6 @@ namespace cuttlefish { -// Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the -// headers -static constexpr size_t VBMETA_MAX_SIZE = 65536ul; - Result<void> RepackBootImage(const Avb& avb, const std::string& new_kernel_path, const std::string& boot_image_path, diff --git a/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp index 616d86f30..7960b631b 100644 --- a/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp +++ b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp @@ -16,6 +16,7 @@ #include "host/commands/assemble_cvd/disk/disk.h" +#include <memory> #include <string> #include <unordered_set> @@ -27,15 +28,13 @@ #include "common/libs/utils/result.h" #include "common/libs/utils/size_utils.h" #include "host/commands/assemble_cvd/bootconfig_args.h" +#include "host/libs/avb/avb.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/data_image.h" #include "host/libs/config/feature.h" #include "host/libs/config/known_paths.h" #include "host/libs/vm_manager/gem5_manager.h" -// Taken from external/avb/avbtool.py; this define is not in the headers -#define MAX_AVB_METADATA_SIZE 69632ul - namespace cuttlefish { Result<void> GeneratePersistentBootconfig( @@ -87,25 +86,11 @@ Result<void> GeneratePersistentBootconfig( } else { bootconfig_fd->Close(); const off_t bootconfig_size_bytes = AlignToPowerOf2( - MAX_AVB_METADATA_SIZE + bootconfig.size(), PARTITION_SIZE_SHIFT); + kMaxAvbMetadataSize + bootconfig.size(), PARTITION_SIZE_SHIFT); - auto avbtool_path = HostBinaryPath("avbtool"); - Command bootconfig_hash_footer_cmd(avbtool_path); - bootconfig_hash_footer_cmd.AddParameter("add_hash_footer"); - bootconfig_hash_footer_cmd.AddParameter("--image"); - bootconfig_hash_footer_cmd.AddParameter(bootconfig_path); - bootconfig_hash_footer_cmd.AddParameter("--partition_size"); - bootconfig_hash_footer_cmd.AddParameter(bootconfig_size_bytes); - bootconfig_hash_footer_cmd.AddParameter("--partition_name"); - bootconfig_hash_footer_cmd.AddParameter("bootconfig"); - bootconfig_hash_footer_cmd.AddParameter("--key"); - bootconfig_hash_footer_cmd.AddParameter(TestKeyRsa4096()); - bootconfig_hash_footer_cmd.AddParameter("--algorithm"); - bootconfig_hash_footer_cmd.AddParameter("SHA256_RSA4096"); - int success = bootconfig_hash_footer_cmd.Start().Wait(); - CF_EXPECT( - success == 0, - "Unable to run append hash footer. Exited with status " << success); + std::unique_ptr<Avb> avbtool = GetDefaultAvb(); + CF_EXPECT(avbtool->AddHashFooter(bootconfig_path, "bootconfig", + bootconfig_size_bytes)); } return {}; } diff --git a/host/commands/assemble_cvd/disk/generate_persistent_vbmeta.cpp b/host/commands/assemble_cvd/disk/generate_persistent_vbmeta.cpp index 4d91d7472..add41dc07 100644 --- a/host/commands/assemble_cvd/disk/generate_persistent_vbmeta.cpp +++ b/host/commands/assemble_cvd/disk/generate_persistent_vbmeta.cpp @@ -31,46 +31,25 @@ namespace cuttlefish { using APBootFlow = CuttlefishConfig::InstanceSpecific::APBootFlow; static bool PrepareVBMetaImage(const std::string& path, bool has_boot_config) { - auto avbtool_path = HostBinaryPath("avbtool"); - Command vbmeta_cmd(avbtool_path); - vbmeta_cmd.AddParameter("make_vbmeta_image"); - vbmeta_cmd.AddParameter("--output"); - vbmeta_cmd.AddParameter(path); - vbmeta_cmd.AddParameter("--algorithm"); - vbmeta_cmd.AddParameter("SHA256_RSA4096"); - vbmeta_cmd.AddParameter("--key"); - vbmeta_cmd.AddParameter(TestKeyRsa4096()); - - vbmeta_cmd.AddParameter("--chain_partition"); - vbmeta_cmd.AddParameter("uboot_env:1:" + TestPubKeyRsa4096()); - + std::unique_ptr<Avb> avbtool = GetDefaultAvb(); + std::vector<ChainPartition> chained_partitions = {ChainPartition{ + .name = "uboot_env", + .rollback_index = "1", + .key_path = TestPubKeyRsa4096(), + }}; if (has_boot_config) { - vbmeta_cmd.AddParameter("--chain_partition"); - vbmeta_cmd.AddParameter("bootconfig:2:" + TestPubKeyRsa4096()); + chained_partitions.emplace_back(ChainPartition{ + .name = "bootconfig", + .rollback_index = "2", + .key_path = TestPubKeyRsa4096(), + }); } - - bool success = vbmeta_cmd.Start().Wait(); - if (success != 0) { - LOG(ERROR) << "Unable to create persistent vbmeta. Exited with status " - << success; + Result<void> result = + avbtool->MakeVbMetaImage(path, chained_partitions, {}, {}); + if (!result.ok()) { + LOG(ERROR) << result.error().Trace(); return false; } - - const auto vbmeta_size = FileSize(path); - if (vbmeta_size > VBMETA_MAX_SIZE) { - LOG(ERROR) << "Generated vbmeta - " << path - << " is larger than the expected " << VBMETA_MAX_SIZE - << ". Stopping."; - return false; - } - if (vbmeta_size != VBMETA_MAX_SIZE) { - auto fd = SharedFD::Open(path, O_RDWR); - if (!fd->IsOpen() || fd->Truncate(VBMETA_MAX_SIZE) != 0) { - LOG(ERROR) << "`truncate --size=" << VBMETA_MAX_SIZE << " " << path - << "` failed: " << fd->StrError(); - return false; - } - } return true; } diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc index 7bc0c436e..6f23e0323 100644 --- a/host/commands/assemble_cvd/disk_flags.cc +++ b/host/commands/assemble_cvd/disk_flags.cc @@ -16,15 +16,18 @@ #include "host/commands/assemble_cvd/disk_flags.h" +#include <sys/statvfs.h> + +#include <fstream> +#include <string> +#include <vector> + #include <android-base/logging.h> #include <android-base/parsebool.h> #include <android-base/parseint.h> #include <android-base/strings.h> #include <fruit/fruit.h> #include <gflags/gflags.h> -#include <sys/statvfs.h> - -#include <fstream> #include "common/libs/fs/shared_buf.h" #include "common/libs/utils/files.h" @@ -40,6 +43,7 @@ #include "host/commands/assemble_cvd/flags_defaults.h" #include "host/commands/assemble_cvd/super_image_mixer.h" #include "host/commands/assemble_cvd/vendor_dlkm_utils.h" +#include "host/libs/avb/avb.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/data_image.h" #include "host/libs/config/inject.h" @@ -356,14 +360,18 @@ std::vector<ImagePartition> android_composite_disk_config( .image_file_path = AbsolutePath(instance.new_vendor_boot_image()), .read_only = FLAGS_use_overlay, }); + auto vbmeta_image = instance.new_vbmeta_image(); + if (!FileExists(vbmeta_image)) { + vbmeta_image = instance.vbmeta_image(); + } partitions.push_back(ImagePartition{ .label = "vbmeta_a", - .image_file_path = AbsolutePath(instance.vbmeta_image()), + .image_file_path = AbsolutePath(vbmeta_image), .read_only = FLAGS_use_overlay, }); partitions.push_back(ImagePartition{ .label = "vbmeta_b", - .image_file_path = AbsolutePath(instance.vbmeta_image()), + .image_file_path = AbsolutePath(vbmeta_image), .read_only = FLAGS_use_overlay, }); partitions.push_back(ImagePartition{ @@ -630,20 +638,13 @@ Result<void> VbmetaEnforceMinimumSize( // libavb expects to be able to read the maximum vbmeta size, so we must // provide a partition which matches this or the read will fail for (const auto& vbmeta_image : - {instance.vbmeta_image(), instance.vbmeta_system_image(), - instance.vbmeta_vendor_dlkm_image(), + {instance.vbmeta_image(), instance.new_vbmeta_image(), + instance.vbmeta_system_image(), instance.vbmeta_vendor_dlkm_image(), instance.vbmeta_system_dlkm_image()}) { // In some configurations of cuttlefish, the vendor dlkm vbmeta image does // not exist - if (FileExists(vbmeta_image) && FileSize(vbmeta_image) != VBMETA_MAX_SIZE) { - auto fd = SharedFD::Open(vbmeta_image, O_RDWR); - CF_EXPECTF(fd->IsOpen(), "Could not open \"{}\": {}", vbmeta_image, - fd->StrError()); - CF_EXPECTF(fd->Truncate(VBMETA_MAX_SIZE) == 0, - "`truncate --size={} {}` failed: {}", VBMETA_MAX_SIZE, - vbmeta_image, fd->StrError()); - CF_EXPECTF(fd->Fsync() == 0, "fsync on `{}` failed: {}", vbmeta_image, - fd->StrError()); + if (FileExists(vbmeta_image)) { + CF_EXPECT(EnforceVbMetaSize(vbmeta_image)); } } return {}; @@ -971,6 +972,9 @@ Result<void> DiskImageFlagsVectorization(CuttlefishConfig& config, const Fetcher const std::string new_super_image_path = const_instance.PerInstancePath("super.img"); instance.set_new_super_image(new_super_image_path); + const std::string new_vbmeta_image_path = + const_instance.PerInstancePath("os_vbmeta.img"); + instance.set_new_vbmeta_image(new_vbmeta_image_path); } instance.set_new_vbmeta_vendor_dlkm_image( diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc index c1e8b8767..4a74ac5e7 100644 --- a/host/commands/assemble_cvd/flags.cc +++ b/host/commands/assemble_cvd/flags.cc @@ -134,7 +134,7 @@ DEFINE_vec(use_random_serial, fmt::format("{}", CF_DEFAULTS_USE_RANDOM_SERIAL), DEFINE_vec(vm_manager, CF_DEFAULTS_VM_MANAGER, "What virtual machine manager to use, one of {qemu_cli, crosvm}"); DEFINE_vec(gpu_mode, CF_DEFAULTS_GPU_MODE, - "What gpu configuration to use, one of {auto, drm_virgl, " + "What gpu configuration to use, one of {auto, custom, drm_virgl, " "gfxstream, gfxstream_guest_angle, " "gfxstream_guest_angle_host_swiftshader, guest_swiftshader}"); DEFINE_vec(gpu_vhost_user_mode, @@ -155,6 +155,22 @@ DEFINE_vec( "be a semicolon separated list of \"<feature name>:[enabled|disabled]\"" "pairs."); +DEFINE_vec(gpu_context_types, CF_DEFAULTS_GPU_CONTEXT_TYPES, + "A colon separated list of virtio-gpu context types. Only valid " + "with --gpu_mode=custom." + " For example \"--gpu_context_types=cross_domain:gfxstream\""); + +DEFINE_vec( + guest_vulkan_driver, CF_DEFAULTS_GUEST_VULKAN_DRIVER, + "Vulkan driver to use with Cuttlefish. Android VMs require specifying " + "this at boot time. Only valid with --gpu_mode=custom. " + "For example \"--guest_vulkan_driver=ranchu\""); + +DEFINE_vec( + frames_socket_path, CF_DEFAULTS_FRAME_SOCKET_PATH, + "Frame socket path to use when launching a VM " + "For example, \"--frames_socket_path=${XDG_RUNTIME_DIR}/wayland-0\""); + DEFINE_vec(use_allocd, CF_DEFAULTS_USE_ALLOCD?"true":"false", "Acquire static resources from the resource allocator daemon."); DEFINE_vec( @@ -435,6 +451,9 @@ DEFINE_vec(mte, fmt::format("{}", CF_DEFAULTS_MTE), "Enable MTE"); DEFINE_vec(enable_audio, fmt::format("{}", CF_DEFAULTS_ENABLE_AUDIO), "Whether to play or capture audio"); +DEFINE_vec(enable_usb, fmt::format("{}", CF_DEFAULTS_ENABLE_USB), + "Whether to allow USB passthrough on the device"); + DEFINE_vec(camera_server_port, std::to_string(CF_DEFAULTS_CAMERA_SERVER_PORT), "camera vsock port"); @@ -524,7 +543,7 @@ Result<std::string> GetAndroidInfoConfig( CF_EXPECT(FileExists(android_info_file_path)); std::string android_info_contents = ReadFile(android_info_file_path); - auto android_info_map = ParseMiscInfo(android_info_contents); + auto android_info_map = CF_EXPECT(ParseMiscInfo(android_info_contents)); CF_EXPECT(android_info_map.find(key) != android_info_map.end()); return android_info_map[key]; } @@ -885,6 +904,14 @@ Result<void> CheckSnapshotCompatible( "--enable_virtiofs=false"); /* + * TODO(khei@): delete this block once usb is supported + */ + CF_EXPECTF(gflags::GetCommandLineFlagInfoOrDie("enable_usb").current_value == + "false", + "--enable_usb should be false for snapshot, consider \"{}\"", + "--enable_usb=false"); + + /* * TODO(kwstephenkim@): delete this block once 3D gpu mode snapshots are * supported */ @@ -1076,6 +1103,7 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( modem_simulator_sim_type)); std::vector<bool> console_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(console)); std::vector<bool> enable_audio_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_audio)); + std::vector<bool> enable_usb_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_usb)); std::vector<bool> start_gnss_proxy_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE( start_gnss_proxy)); std::vector<bool> enable_bootanimation_vec = @@ -1124,6 +1152,12 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( CF_EXPECT(GET_FLAG_STR_VALUE(gpu_vhost_user_mode)); std::vector<std::string> gpu_renderer_features_vec = CF_EXPECT(GET_FLAG_STR_VALUE(gpu_renderer_features)); + std::vector<std::string> gpu_context_types_vec = + CF_EXPECT(GET_FLAG_STR_VALUE(gpu_context_types)); + std::vector<std::string> guest_vulkan_driver_vec = + CF_EXPECT(GET_FLAG_STR_VALUE(guest_vulkan_driver)); + std::vector<std::string> frames_socket_path_vec = + CF_EXPECT(GET_FLAG_STR_VALUE(frames_socket_path)); std::vector<std::string> gpu_capture_binary_vec = CF_EXPECT(GET_FLAG_STR_VALUE(gpu_capture_binary)); @@ -1301,6 +1335,7 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( guest_configs[instance_index].hctr2_supported ? "hctr2" : "cts"); instance.set_use_allocd(use_allocd_vec[instance_index]); instance.set_enable_audio(enable_audio_vec[instance_index]); + instance.set_enable_usb(enable_usb_vec[instance_index]); instance.set_enable_gnss_grpc_proxy(start_gnss_proxy_vec[instance_index]); instance.set_enable_bootanimation(enable_bootanimation_vec[instance_index]); @@ -1513,8 +1548,8 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( const std::string gpu_mode = CF_EXPECT(ConfigureGpuSettings( gpu_mode_vec[instance_index], gpu_vhost_user_mode_vec[instance_index], gpu_renderer_features_vec[instance_index], - vm_manager_vec[instance_index], guest_configs[instance_index], - instance)); + gpu_context_types_vec[instance_index], vm_manager_vec[instance_index], + guest_configs[instance_index], instance)); calculated_gpu_mode_vec[instance_index] = gpu_mode_vec[instance_index]; instance.set_restart_subprocesses(restart_subprocesses_vec[instance_index]); @@ -1550,6 +1585,16 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( instance.set_enable_gpu_udmabuf(enable_gpu_udmabuf_vec[instance_index]); + instance.set_gpu_context_types(gpu_context_types_vec[instance_index]); + instance.set_guest_vulkan_driver(guest_vulkan_driver_vec[instance_index]); + + if (!frames_socket_path_vec[instance_index].empty()) { + instance.set_frames_socket_path(frames_socket_path_vec[instance_index]); + } else { + instance.set_frames_socket_path( + const_instance.PerInstanceInternalUdsPath("frames.sock")); + } + // 1. Keep original code order SetCommandLineOptionWithMode("enable_sandbox") // then set_enable_sandbox later. // 2. SetCommandLineOptionWithMode condition: if gpu_mode or console, @@ -1775,7 +1820,8 @@ Result<CuttlefishConfig> InitializeCuttlefishConfiguration( .ForEnvironment(environment_name); CF_EXPECT(CheckSnapshotCompatible( FLAGS_snapshot_compatible && - (tmp_config_obj.vm_manager() == CrosvmManager::name()), + (tmp_config_obj.vm_manager() == CrosvmManager::name()) && + instance_nums.size() == 1, calculated_gpu_mode_vec), "The set of flags is incompatible with snapshot"); diff --git a/host/commands/assemble_cvd/flags_defaults.h b/host/commands/assemble_cvd/flags_defaults.h index 1fd1b168a..34d69b38b 100644 --- a/host/commands/assemble_cvd/flags_defaults.h +++ b/host/commands/assemble_cvd/flags_defaults.h @@ -141,6 +141,10 @@ #define CF_DEFAULTS_RECORD_SCREEN false #define CF_DEFAULTS_GPU_CAPTURE_BINARY CF_DEFAULTS_DYNAMIC_STRING #define CF_DEFAULTS_GPU_RENDERER_FEATURES "" +#define CF_DEFAULTS_GPU_CONTEXT_TYPES \ + "gfxstream-vulkan:cross-domain:gfxstream-composer" +#define CF_DEFAULTS_GUEST_VULKAN_DRIVER "ranchu" +#define CF_DEFAULTS_FRAME_SOCKET_PATH "" #define CF_DEFAULTS_ENABLE_GPU_UDMABUF false #define CF_DEFAULTS_ENABLE_GPU_VHOST_USER false #define CF_DEFAULTS_DISPLAY0 CF_DEFAULTS_DYNAMIC_STRING @@ -196,6 +200,9 @@ // Audio default parameters #define CF_DEFAULTS_ENABLE_AUDIO true +// USB Passhtrough default parameters +#define CF_DEFAULTS_ENABLE_USB false + // Streaming default parameters #define CF_DEFAULTS_START_WEBRTC false #define CF_DEFAULTS_START_WEBRTC_SIG_SERVER true diff --git a/host/commands/assemble_cvd/graphics_flags.cc b/host/commands/assemble_cvd/graphics_flags.cc index 72a4c8eb4..e5e7e4424 100644 --- a/host/commands/assemble_cvd/graphics_flags.cc +++ b/host/commands/assemble_cvd/graphics_flags.cc @@ -39,6 +39,7 @@ namespace { enum class RenderingMode { kNone, + kCustom, kGuestSwiftShader, kGfxstream, kGfxstreamGuestAngle, @@ -63,6 +64,9 @@ Result<RenderingMode> GetRenderingMode(const std::string& mode) { if (mode == std::string(kGpuModeGuestSwiftshader)) { return RenderingMode::kGuestSwiftShader; } + if (mode == std::string(kGpuModeCustom)) { + return RenderingMode::kCustom; + } if (mode == std::string(kGpuModeNone)) { return RenderingMode::kNone; } @@ -232,7 +236,7 @@ Result<std::string> SelectGpuMode( const GuestConfig& guest_config, const gfxstream::proto::GraphicsAvailability& graphics_availability) { if (gpu_mode_arg != kGpuModeAuto && gpu_mode_arg != kGpuModeDrmVirgl && - gpu_mode_arg != kGpuModeGfxstream && + gpu_mode_arg != kGpuModeCustom && gpu_mode_arg != kGpuModeGfxstream && gpu_mode_arg != kGpuModeGfxstreamGuestAngle && gpu_mode_arg != kGpuModeGfxstreamGuestAngleHostSwiftShader && gpu_mode_arg != kGpuModeGuestSwiftshader && @@ -256,8 +260,8 @@ Result<std::string> SelectGpuMode( LOG(INFO) << "GPU auto mode: detected prerequisites for accelerated " << "rendering support."; - if (vm_manager == vm_manager::QemuManager::name() && !UseQemu8()) { - LOG(INFO) << "Not using QEMU8: selecting guest swiftshader"; + if (vm_manager == vm_manager::QemuManager::name() && !UseQemuPrebuilt()) { + LOG(INFO) << "Not using QEMU prebuilt (QEMU 8+): selecting guest swiftshader"; return kGpuModeGuestSwiftshader; } else if (!guest_config.gfxstream_supported) { LOG(INFO) << "GPU auto mode: guest does not support gfxstream, " @@ -286,8 +290,8 @@ Result<std::string> SelectGpuMode( "--gpu_mode=auto or --gpu_mode=guest_swiftshader."; } - if (vm_manager == vm_manager::QemuManager::name() && !UseQemu8()) { - LOG(INFO) << "Not using QEMU8: selecting guest swiftshader"; + if (vm_manager == vm_manager::QemuManager::name() && !UseQemuPrebuilt()) { + LOG(INFO) << "Not using QEMU prebuilt (QEMU 8+): selecting guest swiftshader"; return kGpuModeGuestSwiftshader; } } @@ -480,9 +484,13 @@ Result<void> SetGfxstreamFlags( } // namespace +static std::unordered_set<std::string> kSupportedGpuContexts{ + "gfxstream-vulkan", "gfxstream-composer", "cross-domain", "magma"}; + Result<std::string> ConfigureGpuSettings( const std::string& gpu_mode_arg, const std::string& gpu_vhost_user_mode_arg, - const std::string& gpu_renderer_features_arg, const std::string& vm_manager, + const std::string& gpu_renderer_features_arg, + std::string& gpu_context_types_arg, const std::string& vm_manager, const GuestConfig& guest_config, CuttlefishConfig::MutableInstanceSpecific& instance) { #ifdef __APPLE__ @@ -525,6 +533,14 @@ Result<std::string> ConfigureGpuSettings( guest_config, graphics_availability, instance)); } + if (gpu_mode == kGpuModeCustom) { + auto requested_types = android::base::Split(gpu_context_types_arg, ":"); + for (const std::string& requested : requested_types) { + CF_EXPECT(kSupportedGpuContexts.count(requested) == 1, + "unsupported context type: " + requested); + } + } + const auto angle_features = CF_EXPECT(GetNeededAngleFeatures( CF_EXPECT(GetRenderingMode(gpu_mode)), graphics_availability)); instance.set_gpu_angle_feature_overrides_enabled( diff --git a/host/commands/assemble_cvd/graphics_flags.h b/host/commands/assemble_cvd/graphics_flags.h index 04923e974..63a4df13e 100644 --- a/host/commands/assemble_cvd/graphics_flags.h +++ b/host/commands/assemble_cvd/graphics_flags.h @@ -26,7 +26,8 @@ namespace cuttlefish { Result<std::string> ConfigureGpuSettings( const std::string& gpu_mode_arg, const std::string& gpu_vhost_user_mode_arg, - const std::string& gpu_renderer_features_arg, const std::string& vm_manager, + const std::string& gpu_renderer_features_arg, + std::string& gpu_context_types_arg, const std::string& vm_manager, const GuestConfig& guest_config, CuttlefishConfig::MutableInstanceSpecific& instance); diff --git a/host/commands/assemble_cvd/misc_info.cc b/host/commands/assemble_cvd/misc_info.cc index e96099c4d..834cf7389 100644 --- a/host/commands/assemble_cvd/misc_info.cc +++ b/host/commands/assemble_cvd/misc_info.cc @@ -15,15 +15,101 @@ #include "misc_info.h" -#include <algorithm> +#include <array> +#include <memory> +#include <set> +#include <string> +#include <unordered_set> +#include <vector> #include <android-base/logging.h> -#include <android-base/stringprintf.h> +#include <android-base/parseint.h> #include <android-base/strings.h> +#include <fmt/format.h> + +#include "common/libs/fs/shared_buf.h" +#include "common/libs/fs/shared_fd.h" +#include "common/libs/utils/contains.h" +#include "common/libs/utils/result.h" namespace cuttlefish { +namespace { + +constexpr char kDynamicPartitions[] = "dynamic_partition_list"; +constexpr char kGoogleDynamicPartitions[] = "google_dynamic_partitions"; +constexpr char kRollbackIndexSuffix[] = "_rollback_index_location"; +constexpr char kSuperBlockDevices[] = "super_block_devices"; +constexpr char kSuperPartitionGroups[] = "super_partition_groups"; +constexpr char kUseDynamicPartitions[] = "use_dynamic_partitions"; +constexpr std::array kNonPartitionKeysToMerge = { + "ab_update", "default_system_dev_certificate"}; + +Result<std::string> GetExpected(const MiscInfo& misc_info, + const std::string& key) { + auto lookup = misc_info.find(key); + CF_EXPECTF(lookup != misc_info.end(), + "Unable to retrieve expected value from key: {}", key); + return lookup->second; +} + +std::string GetOrDefault(const MiscInfo& misc_info, const std::string& key, + const std::string& default_value) { + auto result = GetExpected(misc_info, key); + return result.ok() ? *result : default_value; +} + +std::string MergePartitionLists(const std::string& vendor, + const std::string& system) { + const std::string full_string = fmt::format("{} {}", vendor, system); + auto full_list = android::base::Tokenize(full_string, " "); + // std::set removes duplicates and orders the elements, which we want + std::set<std::string> full_set(full_list.begin(), full_list.end()); + return android::base::Join(full_set, " "); +} + +std::string GetPartitionList(const MiscInfo& vendor_info, + const MiscInfo& system_info, + const std::string& key) { + std::string vendor_list = GetOrDefault(vendor_info, key, ""); + std::string system_list = GetOrDefault(system_info, key, ""); + return MergePartitionLists(vendor_list, system_list); +} + +std::vector<std::string> GeneratePartitionKeys(const std::string& name) { + std::vector<std::string> result; + result.emplace_back("avb_" + name); + result.emplace_back("avb_" + name + "_algorithm"); + result.emplace_back("avb_" + name + "_key_path"); + result.emplace_back("avb_" + name + kRollbackIndexSuffix); + result.emplace_back("avb_" + name + "_hashtree_enable"); + result.emplace_back("avb_" + name + "_add_hashtree_footer_args"); + result.emplace_back(name + "_disable_sparse"); + result.emplace_back("building_" + name + "_image"); + auto fs_type_key = name + "_fs_type"; + if (name == "system") { + fs_type_key = "fs_type"; + } + result.emplace_back(fs_type_key); + return result; +} + +Result<int> ResolveRollbackIndexConflicts( + const std::string& index_string, + const std::unordered_set<int> used_indices) { + int index; + CF_EXPECTF(android::base::ParseInt(index_string, &index), + "Unable to parse value {} to string. Maybe a wrong or bad value " + "read for the rollback index?", + index_string); + while (Contains(used_indices, index)) { + ++index; + } + return index; +} + +} // namespace -MiscInfo ParseMiscInfo(const std::string& misc_info_contents) { +Result<MiscInfo> ParseMiscInfo(const std::string& misc_info_contents) { auto lines = android::base::Split(misc_info_contents, "\n"); MiscInfo misc_info; for (auto& line : lines) { @@ -37,91 +123,124 @@ MiscInfo ParseMiscInfo(const std::string& misc_info_contents) { continue; } // Not using android::base::Split here to only capture the first = - auto key = android::base::Trim(line.substr(0, eq_pos)); - auto value = android::base::Trim(line.substr(eq_pos + 1)); - if (misc_info.find(key) != misc_info.end() && misc_info[key] != value) { - LOG(ERROR) << "Duplicate key: \"" << key << "\". First value: \"" - << misc_info[key] << "\", Second value: \"" << value << "\""; - return {}; - } + const auto key = android::base::Trim(line.substr(0, eq_pos)); + const auto value = android::base::Trim(line.substr(eq_pos + 1)); + const bool duplicate = Contains(misc_info, key) && misc_info[key] != value; + CF_EXPECTF(!duplicate, + "Duplicate key with different value. key:\"{}\", previous " + "value:\"{}\", this value:\"{}\"", + key, misc_info[key], value); misc_info[key] = value; } return misc_info; } -std::string WriteMiscInfo(const MiscInfo& misc_info) { - std::stringstream out; +Result<void> WriteMiscInfo(const MiscInfo& misc_info, + const std::string& output_path) { + std::stringstream file_content; for (const auto& entry : misc_info) { - out << entry.first << "=" << entry.second << "\n"; + file_content << entry.first << "=" << entry.second << "\n"; } - return out.str(); -} -static const std::string kDynamicPartitions = "dynamic_partition_list"; + SharedFD output_file = SharedFD::Creat(output_path.c_str(), 0644); + CF_EXPECT(output_file->IsOpen(), + "Failed to open output misc file: " << output_file->StrError()); -std::vector<std::string> SuperPartitionComponents(const MiscInfo& info) { - auto value_it = info.find(kDynamicPartitions); - if (value_it == info.end()) { - return {}; + CF_EXPECT( + WriteAll(output_file, file_content.str()) >= 0, + "Failed to write output misc file contents: " << output_file->StrError()); + return {}; +} + +// based on build/make/tools/releasetools/merge/merge_target_files.py +Result<MiscInfo> GetCombinedDynamicPartitions(const MiscInfo& vendor_info, + const MiscInfo& system_info) { + CF_EXPECTF(CF_EXPECT(GetExpected(vendor_info, kDynamicPartitions)) == "true", + "Vendor build must have {}=true", kUseDynamicPartitions); + CF_EXPECTF(CF_EXPECT(GetExpected(system_info, kDynamicPartitions)) == "true", + "System build must have {}=true", kUseDynamicPartitions); + MiscInfo result; + // copy where both files are equal + for (const auto& key_val : vendor_info) { + const auto value_result = GetExpected(system_info, key_val.first); + if (value_result.ok() && *value_result == key_val.second) { + result[key_val.first] = key_val.second; + } } - auto components = android::base::Split(value_it->second, " "); - for (auto& component : components) { - component = android::base::Trim(component); + + result[kDynamicPartitions] = + GetPartitionList(vendor_info, system_info, kDynamicPartitions); + + const auto block_devices_result = + GetExpected(vendor_info, kSuperBlockDevices); + if (block_devices_result.ok()) { + result[kSuperBlockDevices] = *block_devices_result; + for (const auto& block_device : + android::base::Tokenize(result[kSuperBlockDevices], " ")) { + const auto key = "super_" + block_device + "_device_size"; + result[key] = CF_EXPECT(GetExpected(vendor_info, key)); + } } - components.erase(std::remove(components.begin(), components.end(), ""), - components.end()); - return components; -} -static constexpr const char* kGoogleDynamicPartitions = - "google_dynamic_partitions"; -static constexpr const char* kSuperPartitionGroups = "super_partition_groups"; + result[kSuperPartitionGroups] = + CF_EXPECT(GetExpected(vendor_info, kSuperPartitionGroups)); + for (const auto& group : + android::base::Tokenize(result[kSuperPartitionGroups], " ")) { + const auto group_size_key = "super_" + group + "_group_size"; + result[group_size_key] = + CF_EXPECT(GetExpected(vendor_info, group_size_key)); -bool SetSuperPartitionComponents(const std::vector<std::string>& components, - MiscInfo* misc_info) { - auto super_partition_groups = misc_info->find(kSuperPartitionGroups); - if (super_partition_groups == misc_info->end()) { - LOG(ERROR) << "Failed to find super partition groups in misc_info"; - return false; + const auto partition_list_key = "super_" + group + "_partition_list"; + result[partition_list_key] = + GetPartitionList(vendor_info, system_info, partition_list_key); } - // Remove all existing update groups in misc_info - auto update_groups = - android::base::Split(super_partition_groups->second, " "); - for (const auto& group_name : update_groups) { - auto partition_list = android::base::StringPrintf("super_%s_partition_list", - group_name.c_str()); - auto partition_size = - android::base::StringPrintf("super_%s_group_size", group_name.c_str()); - for (const auto& key : {partition_list, partition_size}) { - auto it = misc_info->find(key); - if (it == misc_info->end()) { - LOG(ERROR) << "Failed to find " << key << " in misc_info"; - return false; - } - misc_info->erase(it); + // TODO(chadreynolds): add vabc_cow_version logic if we need to support older + // builds + for (const auto& key : + {"virtual_ab", "virtual_ab_retrofit", "lpmake", "super_metadata_device", + "super_partition_error_limit", "super_partition_size"}) { + const auto value_result = GetExpected(vendor_info, key); + if (value_result.ok()) { + result[key] = *value_result; } } + return std::move(result); +} - // For merged target-file, put all dynamic partitions under the - // google_dynamic_partitions update group. - // TODO(xunchang) use different update groups for system and vendor images. - (*misc_info)[kDynamicPartitions] = android::base::Join(components, " "); - (*misc_info)[kSuperPartitionGroups] = kGoogleDynamicPartitions; - std::string partitions_list_key = android::base::StringPrintf( - "super_%s_partition_list", kGoogleDynamicPartitions); - (*misc_info)[partitions_list_key] = android::base::Join(components, " "); - - // Use the entire super partition as the group size - std::string group_size_key = android::base::StringPrintf( - "super_%s_group_size", kGoogleDynamicPartitions); - auto super_size_it = misc_info->find("super_partition_size"); - if (super_size_it == misc_info->end()) { - LOG(ERROR) << "Failed to find super partition size"; - return false; +Result<MiscInfo> MergeMiscInfos( + const MiscInfo& vendor_info, const MiscInfo& system_info, + const MiscInfo& combined_dp_info, + const std::vector<std::string>& system_partitions) { + // the combined misc info uses the vendor values as defaults + MiscInfo result = vendor_info; + std::unordered_set<int> used_indices; + for (const auto& partition : system_partitions) { + for (const auto& key : GeneratePartitionKeys(partition)) { + if (!Contains(system_info, key)) { + continue; + } + auto system_value = system_info.find(key)->second; + // avb_<partition>_rollback_index_location values can conflict across + // different builds + if (android::base::EndsWith(key, kRollbackIndexSuffix)) { + const auto index = CF_EXPECT( + ResolveRollbackIndexConflicts(system_value, used_indices)); + used_indices.insert(index); + system_value = std::to_string(index); + } + result[key] = system_value; + } + } + for (const auto& key : kNonPartitionKeysToMerge) { + if (Contains(system_info, key)) { + result[key] = system_info.find(key)->second; + } + } + for (const auto& key_val : combined_dp_info) { + result[key_val.first] = key_val.second; } - (*misc_info)[group_size_key] = super_size_it->second; - return true; + return std::move(result); } } // namespace cuttlefish diff --git a/host/commands/assemble_cvd/misc_info.h b/host/commands/assemble_cvd/misc_info.h index aa130bcc9..9b018bd43 100644 --- a/host/commands/assemble_cvd/misc_info.h +++ b/host/commands/assemble_cvd/misc_info.h @@ -19,15 +19,22 @@ #include <string> #include <vector> +#include "common/libs/utils/result.h" + namespace cuttlefish { +// TODO(chadreynolds): rename MiscInfo to more generic KeyValueFile since this +// logic is processing multiple filetypes now using MiscInfo = std::map<std::string, std::string>; -MiscInfo ParseMiscInfo(const std::string& file_contents); -std::string WriteMiscInfo(const MiscInfo& info); - -std::vector<std::string> SuperPartitionComponents(const MiscInfo&); -bool SetSuperPartitionComponents(const std::vector<std::string>& components, - MiscInfo* misc_info); +Result<MiscInfo> ParseMiscInfo(const std::string& file_contents); +Result<void> WriteMiscInfo(const MiscInfo& misc_info, + const std::string& output_path); +Result<MiscInfo> GetCombinedDynamicPartitions(const MiscInfo& vendor_info, + const MiscInfo& system_info); +Result<MiscInfo> MergeMiscInfos( + const MiscInfo& vendor_info, const MiscInfo& system_info, + const MiscInfo& combined_dp_info, + const std::vector<std::string>& system_partitions); } // namespace cuttlefish diff --git a/host/commands/assemble_cvd/super_image_mixer.cc b/host/commands/assemble_cvd/super_image_mixer.cc index f8ebf7f38..0cf46707d 100644 --- a/host/commands/assemble_cvd/super_image_mixer.cc +++ b/host/commands/assemble_cvd/super_image_mixer.cc @@ -20,93 +20,59 @@ #include <algorithm> #include <array> #include <memory> +#include <string> +#include <unordered_set> +#include <vector> #include <android-base/strings.h> #include <android-base/logging.h> -#include "common/libs/fs/shared_buf.h" #include "common/libs/utils/archive.h" #include "common/libs/utils/contains.h" #include "common/libs/utils/files.h" +#include "common/libs/utils/result.h" #include "common/libs/utils/subprocess.h" #include "host/commands/assemble_cvd/misc_info.h" +#include "host/libs/config/config_utils.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/fetcher_config.h" namespace cuttlefish { - -Result<bool> SuperImageNeedsRebuilding(const FetcherConfig& fetcher_config, - const std::string& default_target_zip, - const std::string& system_target_zip) { - bool has_default_target_zip = false; - bool has_system_target_zip = false; - if (default_target_zip != "" && - default_target_zip != "unset") { - has_default_target_zip = true; - } - if (system_target_zip != "" && - system_target_zip != "unset") { - has_system_target_zip = true; - } - CF_EXPECT(has_default_target_zip == has_system_target_zip, - "default_target_zip and system_target_zip " - "flags must be specified together"); - // at this time, both should be the same, either true or false - // therefore, I only check one variable - if (has_default_target_zip) { - return true; - } - - bool has_default_build = false; - bool has_system_build = false; - for (const auto& file_iter : fetcher_config.get_cvd_files()) { - if (file_iter.second.source == FileSource::DEFAULT_BUILD) { - has_default_build = true; - } else if (file_iter.second.source == FileSource::SYSTEM_BUILD) { - has_system_build = true; - } - } - return has_default_build && has_system_build; -} - namespace { -std::string TargetFilesZip(const FetcherConfig& fetcher_config, - FileSource source) { - for (const auto& file_iter : fetcher_config.get_cvd_files()) { - const auto& file_path = file_iter.first; - const auto& file_info = file_iter.second; - if (file_info.source != source) { - continue; - } - std::string expected_filename = "target_files-" + file_iter.second.build_id; - if (file_path.find(expected_filename) != std::string::npos) { - return file_path; - } - } - return ""; -} - constexpr char kMiscInfoPath[] = "META/misc_info.txt"; -constexpr std::array kDefaultTargetImages = { +constexpr char kDynamicPartitionsPath[] = "META/dynamic_partitions_info.txt"; +constexpr std::array kVendorTargetImages = { "IMAGES/boot.img", + "IMAGES/dtbo.img", + "IMAGES/init_boot.img", "IMAGES/odm.img", "IMAGES/odm_dlkm.img", "IMAGES/recovery.img", + "IMAGES/system_dlkm.img", "IMAGES/userdata.img", "IMAGES/vbmeta.img", + "IMAGES/vbmeta_system_dlkm.img", + "IMAGES/vbmeta_vendor.img", + "IMAGES/vbmeta_vendor_dlkm.img", "IMAGES/vendor.img", "IMAGES/vendor_dlkm.img", - "IMAGES/vbmeta_vendor_dlkm.img", - "IMAGES/system_dlkm.img", + "IMAGES/vendor_kernel_boot.img", }; -constexpr std::array kDefaultTargetBuildProp = { +constexpr std::array kVendorTargetBuildProps = { "ODM/build.prop", "ODM/etc/build.prop", "VENDOR/build.prop", "VENDOR/etc/build.prop", }; +struct TargetFiles { + Archive vendor_zip; + Archive system_zip; + std::vector<std::string> vendor_contents; + std::vector<std::string> system_contents; +}; + void FindImports(Archive* archive, const std::string& build_prop_file) { auto contents = archive->ExtractToMemory(build_prop_file); auto lines = android::base::Split(contents, "\n"); @@ -118,119 +84,139 @@ void FindImports(Archive* archive, const std::string& build_prop_file) { } } -Result<void> CombineTargetZipFiles(const std::string& default_target_zip, - const std::string& system_target_zip, - const std::string& output_path) { - Archive default_target_archive(default_target_zip); - auto default_target_contents = default_target_archive.Contents(); - CF_EXPECT(default_target_contents.size() != 0, - "Could not open " << default_target_zip); - - Archive system_target_archive(system_target_zip); - auto system_target_contents = system_target_archive.Contents(); - CF_EXPECT(system_target_contents.size() != 0, - "Could not open " << system_target_zip); - - CF_EXPECT( - mkdir(output_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) >= 0, - "Could not create directory " << output_path); - - std::string output_meta = output_path + "/META"; - CF_EXPECT( - mkdir(output_meta.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) >= 0, - "Could not create directory " << output_meta); - - CF_EXPECT( - std::find(default_target_contents.begin(), default_target_contents.end(), - kMiscInfoPath) != default_target_contents.end(), - "Default target files zip does not have " << kMiscInfoPath); - - CF_EXPECT( - std::find(system_target_contents.begin(), system_target_contents.end(), - kMiscInfoPath) != system_target_contents.end(), - "System target files zip does not have " << kMiscInfoPath); - - const auto default_misc = - ParseMiscInfo(default_target_archive.ExtractToMemory(kMiscInfoPath)); - CF_EXPECT(default_misc.size() != 0, - "Could not read the default misc_info.txt file."); - - const auto system_misc = - ParseMiscInfo(system_target_archive.ExtractToMemory(kMiscInfoPath)); - CF_EXPECT(system_misc.size() != 0, - "Could not read the system misc_info.txt file."); - - auto output_misc = default_misc; - auto system_super_partitions = SuperPartitionComponents(system_misc); - // Ensure specific skipped partitions end up in the misc_info.txt - for (auto partition : - {"odm", "odm_dlkm", "vendor", "vendor_dlkm", "system_dlkm"}) { - if (std::find(system_super_partitions.begin(), system_super_partitions.end(), - partition) == system_super_partitions.end()) { - system_super_partitions.push_back(partition); - } - } - CF_EXPECT(SetSuperPartitionComponents(system_super_partitions, &output_misc), - "Failed to update super partitions components for misc_info"); +bool IsTargetFilesImage(const std::string& filename) { + return android::base::StartsWith(filename, "IMAGES/") && + android::base::EndsWith(filename, ".img"); +} + +bool IsTargetFilesBuildProp(const std::string& filename) { + return android::base::EndsWith(filename, "build.prop"); +} - auto misc_output_path = output_path + "/" + kMiscInfoPath; - SharedFD misc_output_file = - SharedFD::Creat(misc_output_path.c_str(), 0644); - CF_EXPECT(misc_output_file->IsOpen(), "Failed to open output misc file: " - << misc_output_file->StrError()); +std::string GetPartitionNameFromPath(const std::string& path) { + // "IMAGES/<name>.img" -> "<name>" + return path.substr(7, path.length() - 11); +} - CF_EXPECT(WriteAll(misc_output_file, WriteMiscInfo(output_misc)) >= 0, - "Failed to write output misc file contents: " - << misc_output_file->StrError()); +Result<TargetFiles> GetTargetFiles(const std::string& vendor_zip_path, + const std::string& system_zip_path) { + auto result = TargetFiles{ + .vendor_zip = Archive(vendor_zip_path), + .system_zip = Archive(system_zip_path), + }; + result.vendor_contents = result.vendor_zip.Contents(); + result.system_contents = result.system_zip.Contents(); + CF_EXPECTF(!result.vendor_contents.empty(), "Could not open {}", + vendor_zip_path); + CF_EXPECTF(!result.system_contents.empty(), "Could not open {}", + system_zip_path); + return result; +} - for (const auto& name : default_target_contents) { - if (!android::base::StartsWith(name, "IMAGES/")) { - continue; - } else if (!android::base::EndsWith(name, ".img")) { +Result<MiscInfo> CombineDynamicPartitionsInfo(TargetFiles& target_files) { + CF_EXPECTF(Contains(target_files.vendor_contents, kDynamicPartitionsPath), + "Vendor target files zip does not contain {}", + kDynamicPartitionsPath); + CF_EXPECTF(Contains(target_files.system_contents, kDynamicPartitionsPath), + "System target files zip does not contain {}", + kDynamicPartitionsPath); + + const MiscInfo vendor_dp_info = CF_EXPECT(ParseMiscInfo( + target_files.vendor_zip.ExtractToMemory(kDynamicPartitionsPath))); + const MiscInfo system_dp_info = CF_EXPECT(ParseMiscInfo( + target_files.system_zip.ExtractToMemory(kDynamicPartitionsPath))); + + return CF_EXPECT( + GetCombinedDynamicPartitions(vendor_dp_info, system_dp_info)); +} + +Result<void> CombineMiscInfo( + TargetFiles& target_files, const std::string& misc_output_path, + const std::vector<std::string>& system_partitions) { + CF_EXPECTF(Contains(target_files.vendor_contents, kMiscInfoPath), + "Vendor target files zip does not contain {}", kMiscInfoPath); + CF_EXPECTF(Contains(target_files.system_contents, kMiscInfoPath), + "System target files zip does not contain {}", kMiscInfoPath); + + const MiscInfo vendor_misc = CF_EXPECT( + ParseMiscInfo(target_files.vendor_zip.ExtractToMemory(kMiscInfoPath))); + const MiscInfo system_misc = CF_EXPECT( + ParseMiscInfo(target_files.system_zip.ExtractToMemory(kMiscInfoPath))); + + const auto combined_dp_info = + CF_EXPECT(CombineDynamicPartitionsInfo(target_files)); + const auto output_misc = CF_EXPECT(MergeMiscInfos( + vendor_misc, system_misc, combined_dp_info, system_partitions)); + + CF_EXPECT(WriteMiscInfo(output_misc, misc_output_path)); + return {}; +} + +Result<std::vector<std::string>> ExtractTargetFiles( + TargetFiles& target_files, const std::string& combined_output_path) { + for (const auto& name : target_files.vendor_contents) { + if (!IsTargetFilesImage(name)) { continue; - } else if (!Contains(kDefaultTargetImages, name)) { + } else if (!Contains(kVendorTargetImages, name)) { continue; } - LOG(INFO) << "Writing " << name; - CF_EXPECT(default_target_archive.ExtractFiles({name}, output_path), - "Failed to extract " << name << " from the default target zip"); + LOG(INFO) << "Writing " << name << " from vendor target"; + CF_EXPECT( + target_files.vendor_zip.ExtractFiles({name}, combined_output_path), + "Failed to extract " << name << " from the vendor target zip"); } - for (const auto& name : default_target_contents) { - if (!android::base::EndsWith(name, "build.prop")) { + for (const auto& name : target_files.vendor_contents) { + if (!IsTargetFilesBuildProp(name)) { continue; - } else if (!Contains(kDefaultTargetBuildProp, name)) { + } else if (!Contains(kVendorTargetBuildProps, name)) { continue; } - FindImports(&default_target_archive, name); - LOG(INFO) << "Writing " << name; - CF_EXPECT(default_target_archive.ExtractFiles({name}, output_path), - "Failed to extract " << name << " from the default target zip"); + FindImports(&target_files.vendor_zip, name); + LOG(INFO) << "Writing " << name << " from vendor target"; + CF_EXPECT( + target_files.vendor_zip.ExtractFiles({name}, combined_output_path), + "Failed to extract " << name << " from the vendor target zip"); } - for (const auto& name : system_target_contents) { - if (!android::base::StartsWith(name, "IMAGES/")) { - continue; - } else if (!android::base::EndsWith(name, ".img")) { + std::vector<std::string> system_partitions; + for (const auto& name : target_files.system_contents) { + if (!IsTargetFilesImage(name)) { continue; - } else if (Contains(kDefaultTargetImages, name)) { + } else if (Contains(kVendorTargetImages, name)) { continue; } - LOG(INFO) << "Writing " << name; - CF_EXPECT(system_target_archive.ExtractFiles({name}, output_path), - "Failed to extract " << name << " from the system target zip"); + LOG(INFO) << "Writing " << name << " from system target"; + CF_EXPECT( + target_files.system_zip.ExtractFiles({name}, combined_output_path), + "Failed to extract " << name << " from the system target zip"); + system_partitions.emplace_back(GetPartitionNameFromPath(name)); } - for (const auto& name : system_target_contents) { - if (!android::base::EndsWith(name, "build.prop")) { + for (const auto& name : target_files.system_contents) { + if (!IsTargetFilesBuildProp(name)) { continue; - } else if (Contains(kDefaultTargetBuildProp, name)) { + } else if (Contains(kVendorTargetBuildProps, name)) { continue; } - FindImports(&system_target_archive, name); - LOG(INFO) << "Writing " << name; - CF_EXPECT(system_target_archive.ExtractFiles({name}, output_path), - "Failed to extract " << name << " from the default target zip"); + FindImports(&target_files.system_zip, name); + LOG(INFO) << "Writing " << name << " from system target"; + CF_EXPECT( + target_files.system_zip.ExtractFiles({name}, combined_output_path), + "Failed to extract " << name << " from the system target zip"); } + return std::move(system_partitions); +} +Result<void> CombineTargetZipFiles(const std::string& vendor_zip_path, + const std::string& system_zip_path, + const std::string& output_path) { + CF_EXPECT(EnsureDirectoryExists(output_path)); + CF_EXPECT(EnsureDirectoryExists(output_path + "/META")); + auto target_files = + CF_EXPECT(GetTargetFiles(vendor_zip_path, system_zip_path)); + const auto system_partitions = + CF_EXPECT(ExtractTargetFiles(target_files, output_path)); + const auto misc_output_path = output_path + "/" + kMiscInfoPath; + CF_EXPECT(CombineMiscInfo(target_files, misc_output_path, system_partitions)); return {}; } @@ -250,6 +236,22 @@ bool BuildSuperImage(const std::string& combined_target_zip, }) == 0; } +std::string TargetFilesZip(const FetcherConfig& fetcher_config, + FileSource source) { + for (const auto& file_iter : fetcher_config.get_cvd_files()) { + const auto& file_path = file_iter.first; + const auto& file_info = file_iter.second; + if (file_info.source != source) { + continue; + } + std::string expected_filename = "target_files-" + file_iter.second.build_id; + if (file_path.find(expected_filename) != std::string::npos) { + return file_path; + } + } + return ""; +} + Result<void> RebuildSuperImage(const FetcherConfig& fetcher_config, const CuttlefishConfig& config, const std::string& output_path) { @@ -311,6 +313,38 @@ class SuperImageRebuilderImpl : public SuperImageRebuilder { } // namespace +Result<bool> SuperImageNeedsRebuilding(const FetcherConfig& fetcher_config, + const std::string& default_target_zip, + const std::string& system_target_zip) { + bool has_default_target_zip = false; + bool has_system_target_zip = false; + if (default_target_zip != "" && default_target_zip != "unset") { + has_default_target_zip = true; + } + if (system_target_zip != "" && system_target_zip != "unset") { + has_system_target_zip = true; + } + CF_EXPECT(has_default_target_zip == has_system_target_zip, + "default_target_zip and system_target_zip " + "flags must be specified together"); + // at this time, both should be the same, either true or false + // therefore, I only check one variable + if (has_default_target_zip) { + return true; + } + + bool has_default_build = false; + bool has_system_build = false; + for (const auto& file_iter : fetcher_config.get_cvd_files()) { + if (file_iter.second.source == FileSource::DEFAULT_BUILD) { + has_default_build = true; + } else if (file_iter.second.source == FileSource::SYSTEM_BUILD) { + has_system_build = true; + } + } + return has_default_build && has_system_build; +} + fruit::Component<fruit::Required<const FetcherConfig, const CuttlefishConfig, const CuttlefishConfig::InstanceSpecific>, SuperImageRebuilder> @@ -320,4 +354,4 @@ SuperImageRebuilderComponent() { .addMultibinding<SetupFeature, SuperImageRebuilder>(); } -} // namespace cuttlefish +} // namespace cuttlefish diff --git a/host/commands/assemble_cvd/vendor_dlkm_utils.cc b/host/commands/assemble_cvd/vendor_dlkm_utils.cc index ded0baaee..57890e4a7 100644 --- a/host/commands/assemble_cvd/vendor_dlkm_utils.cc +++ b/host/commands/assemble_cvd/vendor_dlkm_utils.cc @@ -291,7 +291,8 @@ bool GenerateFileContexts(const char* output_path, bool AddVbmetaFooter(const std::string& output_image, const std::string& partition_name) { - auto avbtool_path = HostBinaryPath("avbtool"); + // TODO(b/335742241): update to use Avb + auto avbtool_path = AvbToolBinary(); Command avb_cmd(avbtool_path); // Add host binary path to PATH, so that avbtool can locate host util // binaries such as 'fec' @@ -408,41 +409,14 @@ bool BuildVbmetaImage(const std::string& image_path, const std::string& vbmeta_path) { CHECK(!image_path.empty()); CHECK(FileExists(image_path)); - auto avbtool_path = HostBinaryPath("avbtool"); - Command vbmeta_cmd(avbtool_path); - vbmeta_cmd.AddParameter("make_vbmeta_image"); - vbmeta_cmd.AddParameter("--output"); - vbmeta_cmd.AddParameter(vbmeta_path); - vbmeta_cmd.AddParameter("--algorithm"); - vbmeta_cmd.AddParameter("SHA256_RSA4096"); - vbmeta_cmd.AddParameter("--key"); - vbmeta_cmd.AddParameter(TestKeyRsa4096()); - vbmeta_cmd.AddParameter("--include_descriptors_from_image"); - vbmeta_cmd.AddParameter(image_path); - vbmeta_cmd.AddParameter("--padding_size"); - vbmeta_cmd.AddParameter("4096"); - - bool success = vbmeta_cmd.Start().Wait(); - if (success != 0) { - LOG(ERROR) << "Unable to create vbmeta. Exited with status " << success; - return false; - } - const auto vbmeta_size = FileSize(vbmeta_path); - if (vbmeta_size > VBMETA_MAX_SIZE) { - LOG(ERROR) << "Generated vbmeta - " << vbmeta_path - << " is larger than the expected " << VBMETA_MAX_SIZE - << ". Stopping."; + std::unique_ptr<Avb> avbtool = GetDefaultAvb(); + Result<void> result = avbtool->MakeVbMetaImage(vbmeta_path, {}, {image_path}, + {"--padding_size", "4096"}); + if (!result.ok()) { + LOG(ERROR) << result.error().Trace(); return false; } - if (vbmeta_size != VBMETA_MAX_SIZE) { - auto fd = SharedFD::Open(vbmeta_path, O_RDWR | O_CLOEXEC); - if (!fd->IsOpen() || fd->Truncate(VBMETA_MAX_SIZE) != 0) { - LOG(ERROR) << "`truncate --size=" << VBMETA_MAX_SIZE << " " << vbmeta_path - << "` failed: " << fd->StrError(); - return false; - } - } return true; } diff --git a/host/commands/run_cvd/boot_state_machine.cc b/host/commands/run_cvd/boot_state_machine.cc index cc9f09441..67060e07a 100644 --- a/host/commands/run_cvd/boot_state_machine.cc +++ b/host/commands/run_cvd/boot_state_machine.cc @@ -51,7 +51,7 @@ namespace { // when the boot finishes. // * When restoring from a snapshot, `DaemonizeLauncher` returns an invalid // `SharedFD`. The child is expected to write an arbitrary byte to the -// instance's "restore_pipe" and then the child assumes the restore was +// instance's "restore_pipe" and then the parent assumes the restore was // successful. // // We should consider unifying these two types of pipes. diff --git a/host/commands/run_cvd/launch/modem.cpp b/host/commands/run_cvd/launch/modem.cpp index 2502d86a2..af6c0dc57 100644 --- a/host/commands/run_cvd/launch/modem.cpp +++ b/host/commands/run_cvd/launch/modem.cpp @@ -31,33 +31,33 @@ namespace cuttlefish { -static bool StopModemSimulator(int id) { +static StopperResult StopModemSimulator(int id) { std::string socket_name = "modem_simulator" + std::to_string(id); auto monitor_sock = SharedFD::SocketLocalClient(socket_name, true, SOCK_STREAM); if (!monitor_sock->IsOpen()) { LOG(ERROR) << "The connection to modem simulator is closed"; - return false; + return StopperResult::kStopFailure; } std::string msg("STOP"); if (monitor_sock->Write(msg.data(), msg.size()) < 0) { monitor_sock->Close(); LOG(ERROR) << "Failed to send 'STOP' to modem simulator"; - return false; + return StopperResult::kStopFailure; } char buf[64] = {0}; if (monitor_sock->Read(buf, sizeof(buf)) <= 0) { monitor_sock->Close(); LOG(ERROR) << "Failed to read message from modem simulator"; - return false; + return StopperResult::kStopFailure; } if (strcmp(buf, "OK")) { monitor_sock->Close(); LOG(ERROR) << "Read '" << buf << "' instead of 'OK' from modem simulator"; - return false; + return StopperResult::kStopFailure; } - return true; + return StopperResult::kStopSuccess; } Result<std::optional<MonitorCommand>> ModemSimulator( @@ -89,18 +89,9 @@ Result<std::optional<MonitorCommand>> ModemSimulator( sockets.emplace_back(std::move(modem_sim_socket)); } - auto host_id = instance.modem_simulator_host_id(); - Command cmd(ModemSimulatorBinary(), [host_id](Subprocess* proc) { - auto stopped = StopModemSimulator(host_id); - if (stopped) { - return StopperResult::kStopSuccess; - } - LOG(WARNING) << "Failed to stop modem simulator nicely, " - << "attempting to KILL"; - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - }); + auto id = instance.modem_simulator_host_id(); + auto nice_stop = [id]() { return StopModemSimulator(id); }; + Command cmd(ModemSimulatorBinary(), KillSubprocessFallback(nice_stop)); auto sim_type = instance.modem_simulator_sim_type(); cmd.AddParameter(std::string{"-sim_type="} + std::to_string(sim_type)); diff --git a/host/commands/run_cvd/launch/streamer.cpp b/host/commands/run_cvd/launch/streamer.cpp index 4ed0d5c2e..3334efdf1 100644 --- a/host/commands/run_cvd/launch/streamer.cpp +++ b/host/commands/run_cvd/launch/streamer.cpp @@ -250,14 +250,12 @@ class WebRtcServer : public virtual CommandSource, commands.emplace_back(std::move(sig_proxy)); } - auto stopper = [webrtc_recorder = webrtc_recorder_](Subprocess* proc) { + auto stopper = [webrtc_recorder = webrtc_recorder_]() { webrtc_recorder.SendStopRecordingCommand(); - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; + return StopperResult::kStopFailure; }; - Command webrtc(WebRtcBinary(), stopper); + Command webrtc(WebRtcBinary(), KillSubprocessFallback(stopper)); webrtc.AddParameter("-group_id=", instance_.group_id()); diff --git a/host/commands/start/main.cc b/host/commands/start/main.cc index 1f5ca8d07..e0c035f9c 100644 --- a/host/commands/start/main.cc +++ b/host/commands/start/main.cc @@ -250,6 +250,7 @@ std::unordered_set<std::string> kBoolFlags = { "console", "enable_sandbox", "enable_virtiofs", + "enable_usb", "restart_subprocesses", "enable_gpu_udmabuf", "enable_gpu_vhost_user", diff --git a/host/libs/avb/Android.bp b/host/libs/avb/Android.bp index 62b6ad74e..3c198acef 100644 --- a/host/libs/avb/Android.bp +++ b/host/libs/avb/Android.bp @@ -23,6 +23,7 @@ cc_library { "avb.cpp" ], shared_libs: [ + "libcuttlefish_fs", "libcuttlefish_utils", "libfruit", "libjsoncpp", // need to access host/libs/config/cuttlefish_config.h diff --git a/host/libs/avb/avb.cpp b/host/libs/avb/avb.cpp index 3b6732bd5..6ffa0aba6 100644 --- a/host/libs/avb/avb.cpp +++ b/host/libs/avb/avb.cpp @@ -17,45 +17,164 @@ #include "host/libs/avb/avb.h" +#include <fcntl.h> + +#include <memory> +#include <string> + +#include <fruit/fruit.h> + +#include "common/libs/fs/shared_fd.h" +#include "common/libs/utils/files.h" +#include "common/libs/utils/result.h" #include "common/libs/utils/subprocess.h" #include "host/libs/config/cuttlefish_config.h" #include "host/libs/config/known_paths.h" namespace cuttlefish { +namespace { + +constexpr char kAddHashFooter[] = "add_hash_footer"; +constexpr char kDefaultAlgorithm[] = "SHA256_RSA4096"; +constexpr char kInfoImage[] = "info_image"; +constexpr char kMakeVbmetaImage[] = "make_vbmeta_image"; +// Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the +// headers +constexpr size_t kVbMetaMaxSize = 65536ul; + +} // namespace + +Avb::Avb(std::string avbtool_path) : avbtool_path_(std::move(avbtool_path)) {} Avb::Avb(std::string avbtool_path, std::string algorithm, std::string key) : avbtool_path_(std::move(avbtool_path)), algorithm_(std::move(algorithm)), key_(std::move(key)) {} +Command Avb::GenerateAddHashFooter(const std::string& image_path, + const std::string& partition_name, + const off_t partition_size_bytes) const { + Command command(avbtool_path_); + command.AddParameter(kAddHashFooter); + if (!algorithm_.empty()) { + command.AddParameter("--algorithm"); + command.AddParameter(algorithm_); + } + if (!key_.empty()) { + command.AddParameter("--key"); + command.AddParameter(key_); + } + command.AddParameter("--image"); + command.AddParameter(image_path); + command.AddParameter("--partition_name"); + command.AddParameter(partition_name); + command.AddParameter("--partition_size"); + command.AddParameter(partition_size_bytes); + return std::move(command); +} + Result<void> Avb::AddHashFooter(const std::string& image_path, const std::string& partition_name, - off_t partition_size_bytes) const { - int res; - - Command avb_cmd(avbtool_path_); - avb_cmd.AddParameter("add_hash_footer"); - avb_cmd.AddParameter("--image"); - avb_cmd.AddParameter(image_path); - avb_cmd.AddParameter("--partition_size"); - avb_cmd.AddParameter(partition_size_bytes); - avb_cmd.AddParameter("--partition_name"); - avb_cmd.AddParameter(partition_name); - avb_cmd.AddParameter("--key"); - avb_cmd.AddParameter(key_); - avb_cmd.AddParameter("--algorithm"); - avb_cmd.AddParameter(algorithm_); - res = avb_cmd.Start().Wait(); - - CF_EXPECT(res == 0, "Unable to run avbtool. Exited with status " << res); + const off_t partition_size_bytes) const { + auto command = + GenerateAddHashFooter(image_path, partition_name, partition_size_bytes); + int exit_code = command.Start().Wait(); + CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}", + command.Executable(), kAddHashFooter, exit_code); + return {}; +} + +Command Avb::GenerateInfoImage(const std::string& image_path, + const SharedFD& output_file) const { + Command command(avbtool_path_); + command.AddParameter(kInfoImage); + command.AddParameter("--image"); + command.AddParameter(image_path); + command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, output_file); + return command; +} + +Result<void> Avb::WriteInfoImage(const std::string& image_path, + const std::string& output_path) const { + auto output_file = SharedFD::Creat(output_path, 0666); + CF_EXPECTF(output_file->IsOpen(), "Unable to create {} with error - {}", + output_path, output_file->StrError()); + auto command = GenerateInfoImage(image_path, output_file); + int exit_code = command.Start().Wait(); + CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}", + command.Executable(), kInfoImage, exit_code); + return {}; +} + +Command Avb::GenerateMakeVbMetaImage( + const std::string& output_path, + const std::vector<ChainPartition>& chained_partitions, + const std::vector<std::string>& included_partitions, + const std::vector<std::string>& extra_arguments) { + Command command(avbtool_path_); + command.AddParameter(kMakeVbmetaImage); + command.AddParameter("--algorithm"); + command.AddParameter(algorithm_); + command.AddParameter("--key"); + command.AddParameter(key_); + command.AddParameter("--output"); + command.AddParameter(output_path); + + for (const auto& partition : chained_partitions) { + const std::string argument = partition.name + ":" + + partition.rollback_index + ":" + + partition.key_path; + command.AddParameter("--chain_partition"); + command.AddParameter(argument); + } + for (const auto& partition : included_partitions) { + command.AddParameter("--include_descriptors_from_image"); + command.AddParameter(partition); + } + for (const auto& extra_arg : extra_arguments) { + command.AddParameter(extra_arg); + } + return command; +} + +Result<void> Avb::MakeVbMetaImage( + const std::string& output_path, + const std::vector<ChainPartition>& chained_partitions, + const std::vector<std::string>& included_partitions, + const std::vector<std::string>& extra_arguments) { + auto command = GenerateMakeVbMetaImage(output_path, chained_partitions, + included_partitions, extra_arguments); + int exit_code = command.Start().Wait(); + CF_EXPECTF(exit_code == 0, "Failure running {} {}. Exited with status {}", + command.Executable(), kMakeVbmetaImage, exit_code); + CF_EXPECT(EnforceVbMetaSize(output_path)); + return {}; +} + +Result<void> EnforceVbMetaSize(const std::string& path) { + const auto vbmeta_size = FileSize(path); + CF_EXPECT_LE(vbmeta_size, kVbMetaMaxSize); + if (vbmeta_size != kVbMetaMaxSize) { + auto vbmeta_fd = SharedFD::Open(path, O_RDWR); + CF_EXPECTF(vbmeta_fd->IsOpen(), "Unable to open {} with error {}", path, + vbmeta_fd->StrError()); + CF_EXPECTF(vbmeta_fd->Truncate(kVbMetaMaxSize) == 0, + "Truncating {} failed with error {}", path, + vbmeta_fd->StrError()); + CF_EXPECTF(vbmeta_fd->Fsync() == 0, "fsync on {} failed with error {}", + path, vbmeta_fd->StrError()); + } return {}; } +std::unique_ptr<Avb> GetDefaultAvb() { + return std::unique_ptr<Avb>( + new Avb(AvbToolBinary(), kDefaultAlgorithm, TestKeyRsa4096())); +} + fruit::Component<Avb> CuttlefishKeyAvbComponent() { - return fruit::createComponent().registerProvider([]() -> Avb* { - return new Avb(HostBinaryPath("avbtool"), "SHA256_RSA4096", - TestKeyRsa4096()); - }); + return fruit::createComponent().registerProvider( + []() -> Avb* { return GetDefaultAvb().release(); }); } } // namespace cuttlefish
\ No newline at end of file diff --git a/host/libs/avb/avb.h b/host/libs/avb/avb.h index cc488c166..ac4a61b89 100644 --- a/host/libs/avb/avb.h +++ b/host/libs/avb/avb.h @@ -19,12 +19,30 @@ #include <sys/types.h> +#include <cstdint> +#include <memory> +#include <string> +#include <vector> + #include <fruit/fruit.h> +#include "common/libs/fs/shared_fd.h" +#include "common/libs/utils/subprocess.h" + namespace cuttlefish { +// Taken from external/avb/avbtool.py; this define is not in the headers +inline constexpr uint64_t kMaxAvbMetadataSize = 69632ul; + +struct ChainPartition { + std::string name; + std::string rollback_index; + std::string key_path; +}; + class Avb { public: + Avb(std::string avbtool_path); Avb(std::string avbtool_path, std::string algorithm, std::string key); /** @@ -37,14 +55,36 @@ class Avb { */ Result<void> AddHashFooter(const std::string& image_path, const std::string& partition_name, - off_t partition_size_bytes) const; + const off_t partition_size_bytes) const; + Result<void> WriteInfoImage(const std::string& image_path, + const std::string& output_path) const; + Result<void> MakeVbMetaImage( + const std::string& output_path, + const std::vector<ChainPartition>& chained_partitions, + const std::vector<std::string>& included_partitions, + const std::vector<std::string>& extra_arguments); private: + Command GenerateAddHashFooter(const std::string& image_path, + const std::string& partition_name, + const off_t partition_size_bytes) const; + Command GenerateInfoImage(const std::string& image_path, + const SharedFD& output_path) const; + Command GenerateMakeVbMetaImage( + const std::string& output_path, + const std::vector<ChainPartition>& chained_partitions, + const std::vector<std::string>& included_partitions, + const std::vector<std::string>& extra_arguments); + std::string avbtool_path_; std::string algorithm_; std::string key_; }; +Result<void> EnforceVbMetaSize(const std::string& path); + +std::unique_ptr<Avb> GetDefaultAvb(); + fruit::Component<Avb> CuttlefishKeyAvbComponent(); } // namespace cuttlefish diff --git a/host/libs/config/config_utils.cpp b/host/libs/config/config_utils.cpp index 9197877dc..c4fea49cc 100644 --- a/host/libs/config/config_utils.cpp +++ b/host/libs/config/config_utils.cpp @@ -24,8 +24,10 @@ #include <android-base/logging.h> #include <android-base/strings.h> +#include "common/libs/utils/contains.h" #include "common/libs/utils/environment.h" #include "host/libs/config/config_constants.h" +#include "host/libs/config/cuttlefish_config.h" namespace cuttlefish { @@ -111,19 +113,17 @@ std::string HostBinaryDir() { return DefaultHostArtifactsPath("bin"); } -bool UseQemu8() { +bool UseQemuPrebuilt() { const std::string target_prod_str = StringFromEnv("TARGET_PRODUCT", ""); - if (HostArch() == Arch::X86_64 && - target_prod_str.find("arm") == std::string::npos) { + if (!Contains(target_prod_str, "arm")) { return true; } - return false; } std::string DefaultQemuBinaryDir() { - if (UseQemu8()) { - return HostBinaryDir(); + if (UseQemuPrebuilt()) { + return HostBinaryDir() + "/" + HostArchStr() + "-linux-gnu/qemu"; } return "/usr/bin"; } @@ -140,6 +140,14 @@ std::string HostUsrSharePath(const std::string& binary_name) { return DefaultHostArtifactsPath("usr/share/" + binary_name); } +std::string HostQemuBiosPath() { + if (UseQemuPrebuilt()) { + return DefaultHostArtifactsPath( + "usr/share/qemu/" + HostArchStr() + "-linux-gnu"); + } + return "/usr/share/qemu"; +} + std::string DefaultGuestImagePath(const std::string& file_name) { return (StringFromEnv("ANDROID_PRODUCT_OUT", StringFromEnv("HOME", "."))) + file_name; diff --git a/host/libs/config/config_utils.h b/host/libs/config/config_utils.h index 8107f5e9b..b5058bb18 100644 --- a/host/libs/config/config_utils.h +++ b/host/libs/config/config_utils.h @@ -51,6 +51,7 @@ std::string DefaultHostArtifactsPath(const std::string& file); std::string DefaultQemuBinaryDir(); std::string HostBinaryPath(const std::string& file); std::string HostUsrSharePath(const std::string& file); +std::string HostQemuBiosPath(); std::string DefaultGuestImagePath(const std::string& file); std::string DefaultEnvironmentPath(const char* environment_key, const char* default_value, @@ -59,6 +60,6 @@ std::string DefaultEnvironmentPath(const char* environment_key, // Whether the host supports qemu bool HostSupportsQemuCli(); -// Whether to use QEMU8 -bool UseQemu8(); +// Whether to use our local QEMU prebuilt +bool UseQemuPrebuilt(); } diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp index ad65c9cbe..6de482552 100644 --- a/host/libs/config/cuttlefish_config.cpp +++ b/host/libs/config/cuttlefish_config.cpp @@ -50,6 +50,7 @@ const char* const kVhostUserVsockModeTrue = "true"; const char* const kVhostUserVsockModeFalse = "false"; const char* const kGpuModeAuto = "auto"; +const char* const kGpuModeCustom = "custom"; const char* const kGpuModeDrmVirgl = "drm_virgl"; const char* const kGpuModeGfxstream = "gfxstream"; const char* const kGpuModeGfxstreamGuestAngle = "gfxstream_guest_angle"; diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h index e4a924806..8de591aa8 100644 --- a/host/libs/config/cuttlefish_config.h +++ b/host/libs/config/cuttlefish_config.h @@ -376,7 +376,6 @@ class CuttlefishConfig { std::string rotary_socket_path() const; std::string keyboard_socket_path() const; std::string switches_socket_path() const; - std::string frames_socket_path() const; std::string access_kregistry_path() const; @@ -509,6 +508,7 @@ class CuttlefishConfig { std::string persistent_bootconfig_path() const; + // used for the persistent_composite_disk vbmeta std::string vbmeta_path() const; std::string ap_vbmeta_path() const; @@ -559,6 +559,7 @@ class CuttlefishConfig { bool enable_audio() const; bool enable_gnss_grpc_proxy() const; bool enable_bootanimation() const; + bool enable_usb() const; std::vector<std::string> extra_bootconfig_args() const; bool record_screen() const; std::string gem5_debug_file() const; @@ -601,6 +602,9 @@ class CuttlefishConfig { std::string gpu_capture_binary() const; std::string gpu_gfxstream_transport() const; std::string gpu_renderer_features() const; + std::string gpu_context_types() const; + std::string guest_vulkan_driver() const; + std::string frames_socket_path() const; std::string gpu_vhost_user_mode() const; @@ -627,6 +631,7 @@ class CuttlefishConfig { std::string vendor_boot_image() const; std::string new_vendor_boot_image() const; std::string vbmeta_image() const; + std::string new_vbmeta_image() const; std::string vbmeta_system_image() const; std::string vbmeta_vendor_dlkm_image() const; std::string new_vbmeta_vendor_dlkm_image() const; @@ -761,6 +766,7 @@ class CuttlefishConfig { void set_pause_in_bootloader(bool pause_in_bootloader); void set_run_as_daemon(bool run_as_daemon); void set_enable_audio(bool enable); + void set_enable_usb(bool enable); void set_enable_gnss_grpc_proxy(const bool enable_gnss_grpc_proxy); void set_enable_bootanimation(const bool enable_bootanimation); void set_extra_bootconfig_args(const std::string& extra_bootconfig_args); @@ -807,6 +813,10 @@ class CuttlefishConfig { void set_gpu_capture_binary(const std::string&); void set_gpu_gfxstream_transport(const std::string& transport); void set_gpu_renderer_features(const std::string& features); + void set_gpu_context_types(const std::string& context_types); + void set_guest_vulkan_driver(const std::string& driver); + void set_frames_socket_path(const std::string& driver); + void set_enable_gpu_udmabuf(const bool enable_gpu_udmabuf); void set_enable_gpu_vhost_user(const bool enable_gpu_vhost_user); void set_enable_gpu_external_blob(const bool enable_gpu_external_blob); @@ -828,6 +838,7 @@ class CuttlefishConfig { void set_vendor_boot_image(const std::string& vendor_boot_image); void set_new_vendor_boot_image(const std::string& new_vendor_boot_image); void set_vbmeta_image(const std::string& vbmeta_image); + void set_new_vbmeta_image(const std::string& new_vbmeta_image); void set_vbmeta_system_image(const std::string& vbmeta_system_image); void set_vbmeta_vendor_dlkm_image( const std::string& vbmeta_vendor_dlkm_image); @@ -969,6 +980,7 @@ extern const char* const kVhostUserVsockModeFalse; // GPU modes extern const char* const kGpuModeAuto; +extern const char* const kGpuModeCustom; extern const char* const kGpuModeDrmVirgl; extern const char* const kGpuModeGfxstream; extern const char* const kGpuModeGfxstreamGuestAngle; diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp index 335c0621a..41c319e5b 100644 --- a/host/libs/config/cuttlefish_config_instance.cpp +++ b/host/libs/config/cuttlefish_config_instance.cpp @@ -192,6 +192,14 @@ void CuttlefishConfig::MutableInstanceSpecific::set_vbmeta_image( const std::string& vbmeta_image) { (*Dictionary())[kVbmetaImage] = vbmeta_image; } +static constexpr char kNewVbmetaImage[] = "new_vbmeta_image"; +std::string CuttlefishConfig::InstanceSpecific::new_vbmeta_image() const { + return (*Dictionary())[kNewVbmetaImage].asString(); +} +void CuttlefishConfig::MutableInstanceSpecific::set_new_vbmeta_image( + const std::string& new_vbmeta_image) { + (*Dictionary())[kNewVbmetaImage] = new_vbmeta_image; +} static constexpr char kVbmetaSystemImage[] = "vbmeta_system_image"; std::string CuttlefishConfig::InstanceSpecific::vbmeta_system_image() const { return (*Dictionary())[kVbmetaSystemImage].asString(); @@ -740,6 +748,24 @@ void CuttlefishConfig::MutableInstanceSpecific::set_gpu_renderer_features( (*Dictionary())[kGpuRendererFeatures] = transport; } +static constexpr char kGpuContextTypes[] = "gpu_context_types"; +std::string CuttlefishConfig::InstanceSpecific::gpu_context_types() const { + return (*Dictionary())[kGpuContextTypes].asString(); +} +void CuttlefishConfig::MutableInstanceSpecific::set_gpu_context_types( + const std::string& context_types) { + (*Dictionary())[kGpuContextTypes] = context_types; +} + +static constexpr char kVulkanDriver[] = "guest_vulkan_driver"; +std::string CuttlefishConfig::InstanceSpecific::guest_vulkan_driver() const { + return (*Dictionary())[kVulkanDriver].asString(); +} +void CuttlefishConfig::MutableInstanceSpecific::set_guest_vulkan_driver( + const std::string& driver) { + (*Dictionary())[kVulkanDriver] = driver; +} + static constexpr char kRestartSubprocesses[] = "restart_subprocesses"; bool CuttlefishConfig::InstanceSpecific::restart_subprocesses() const { return (*Dictionary())[kRestartSubprocesses].asBool(); @@ -816,6 +842,14 @@ void CuttlefishConfig::MutableInstanceSpecific::set_enable_bootanimation( (*Dictionary())[kEnableBootAnimation] = enable_bootanimation; } +static constexpr char kEnableUsb[] = "enable_usb"; +void CuttlefishConfig::MutableInstanceSpecific::set_enable_usb(bool enable) { + (*Dictionary())[kEnableUsb] = enable; +} +bool CuttlefishConfig::InstanceSpecific::enable_usb() const { + return (*Dictionary())[kEnableUsb].asBool(); +} + static constexpr char kExtraBootconfigArgsInstanced[] = "extra_bootconfig_args"; std::vector<std::string> CuttlefishConfig::InstanceSpecific::extra_bootconfig_args() const { @@ -1247,7 +1281,7 @@ std::string CuttlefishConfig::InstanceSpecific::ap_composite_disk_path() } std::string CuttlefishConfig::InstanceSpecific::vbmeta_path() const { - return AbsolutePath(PerInstancePath("vbmeta.img")); + return AbsolutePath(PerInstancePath("persistent_vbmeta.img")); } std::string CuttlefishConfig::InstanceSpecific::ap_vbmeta_path() const { @@ -1713,8 +1747,14 @@ std::string CuttlefishConfig::InstanceSpecific::switches_socket_path() const { return PerInstanceInternalUdsPath("switches.sock"); } +static constexpr char kFrameSockPath[] = "frame_sock_path"; +void CuttlefishConfig::MutableInstanceSpecific::set_frames_socket_path( + const std::string& frame_socket_path) { + (*Dictionary())[kFrameSockPath] = frame_socket_path; +} + std::string CuttlefishConfig::InstanceSpecific::frames_socket_path() const { - return PerInstanceInternalUdsPath("frames.sock"); + return (*Dictionary())[kFrameSockPath].asString(); } static constexpr char kWifiMacPrefix[] = "wifi_mac_prefix"; diff --git a/host/libs/config/known_paths.cpp b/host/libs/config/known_paths.cpp index f8d3c4930..9303fa805 100644 --- a/host/libs/config/known_paths.cpp +++ b/host/libs/config/known_paths.cpp @@ -24,6 +24,8 @@ std::string AdbConnectorBinary() { return HostBinaryPath("adb_connector"); } +std::string AvbToolBinary() { return HostBinaryPath("avbtool"); } + std::string CasimirControlServerBinary() { return HostBinaryPath("casimir_control_server"); } diff --git a/host/libs/config/known_paths.h b/host/libs/config/known_paths.h index 439197d93..0670b644d 100644 --- a/host/libs/config/known_paths.h +++ b/host/libs/config/known_paths.h @@ -20,6 +20,7 @@ namespace cuttlefish { std::string AdbConnectorBinary(); +std::string AvbToolBinary(); std::string CasimirControlServerBinary(); std::string ConfigServerBinary(); std::string ConsoleForwarderBinary(); diff --git a/host/libs/screen_connector/screen_connector.h b/host/libs/screen_connector/screen_connector.h index 634c7adf9..bc56cedf6 100644 --- a/host/libs/screen_connector/screen_connector.h +++ b/host/libs/screen_connector/screen_connector.h @@ -68,7 +68,9 @@ class ScreenConnector : public ScreenConnectorInfo, } auto instance = config->ForDefaultInstance(); std::unordered_set<std::string_view> valid_gpu_modes{ - cuttlefish::kGpuModeDrmVirgl, cuttlefish::kGpuModeGfxstream, + cuttlefish::kGpuModeCustom, + cuttlefish::kGpuModeDrmVirgl, + cuttlefish::kGpuModeGfxstream, cuttlefish::kGpuModeGfxstreamGuestAngle, cuttlefish::kGpuModeGfxstreamGuestAngleHostSwiftShader, cuttlefish::kGpuModeGuestSwiftshader}; diff --git a/host/libs/vm_manager/crosvm_builder.cpp b/host/libs/vm_manager/crosvm_builder.cpp index bef5a6eed..cb863db32 100644 --- a/host/libs/vm_manager/crosvm_builder.cpp +++ b/host/libs/vm_manager/crosvm_builder.cpp @@ -48,18 +48,14 @@ void CrosvmBuilder::ApplyProcessRestarter( void CrosvmBuilder::AddControlSocket(const std::string& control_socket, const std::string& executable_path) { - command_.SetStopper([executable_path, control_socket](Subprocess* proc) { + auto stopper = [executable_path, control_socket]() { Command stop_cmd(executable_path); stop_cmd.AddParameter("stop"); stop_cmd.AddParameter(control_socket); - if (stop_cmd.Start().Wait() == 0) { - return StopperResult::kStopSuccess; - } - LOG(WARNING) << "Failed to stop VMM nicely, attempting to KILL"; - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - }); + return stop_cmd.Start().Wait() == 0 ? StopperResult::kStopSuccess + : StopperResult::kStopFailure; + }; + command_.SetStopper(KillSubprocessFallback(stopper)); command_.AddParameter("--socket=", control_socket); } diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp index 162219baa..c26da188e 100644 --- a/host/libs/vm_manager/crosvm_manager.cpp +++ b/host/libs/vm_manager/crosvm_manager.cpp @@ -1,4 +1,4 @@ -/* +/*crosvm * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -114,6 +114,17 @@ CrosvmManager::ConfigureGraphics( {"androidboot.hardware.gltransport", gfxstream_transport}, {"androidboot.opengles.version", "196609"}, // OpenGL ES 3.1 }; + } else if (instance.gpu_mode() == kGpuModeCustom) { + bootconfig_args = { + {"androidboot.cpuvulkan.version", "0"}, + {"androidboot.hardware.gralloc", "minigbm"}, + {"androidboot.hardware.hwcomposer", instance.hwcomposer()}, + {"androidboot.hardware.hwcomposer.display_finder_mode", "drm"}, + {"androidboot.hardware.egl", "angle"}, + {"androidboot.hardware.vulkan", instance.guest_vulkan_driver()}, + {"androidboot.hardware.gltransport", "virtio-gpu-asg"}, + {"androidboot.opengles.version", "196609"}, // OpenGL ES 3.1 + }; } else if (instance.gpu_mode() == kGpuModeNone) { return {}; } else { @@ -201,12 +212,6 @@ Result<VhostUserDeviceCommands> BuildVhostUserGpu( auto gpu_device_socket_path = instance.PerInstanceInternalUdsPath("vhost-user-gpu-socket"); - auto gpu_device_socket = SharedFD::SocketLocalServer( - gpu_device_socket_path.c_str(), false, SOCK_STREAM, 0777); - CF_EXPECT(gpu_device_socket->IsOpen(), - "Failed to create socket for crosvm vhost user gpu's control" - << gpu_device_socket->StrError()); - auto gpu_device_logs_path = instance.PerInstanceInternalPath("crosvm_vhost_user_gpu.fifo"); auto gpu_device_logs = CF_EXPECT(SharedFD::Fifo(gpu_device_logs_path, 0666)); @@ -214,17 +219,12 @@ Result<VhostUserDeviceCommands> BuildVhostUserGpu( Command gpu_device_logs_cmd(HostBinaryPath("log_tee")); gpu_device_logs_cmd.AddParameter("--process_name=crosvm_gpu"); gpu_device_logs_cmd.AddParameter("--log_fd_in=", gpu_device_logs); - gpu_device_logs_cmd.SetStopper([](Subprocess* proc) { + gpu_device_logs_cmd.SetStopper(KillSubprocessFallback([](Subprocess* proc) { // Ask nicely so that log_tee gets a chance to process all the logs. - int rval = kill(proc->pid(), SIGINT); - if (rval != 0) { - LOG(ERROR) << "Failed to stop log_tee nicely, attempting to KILL"; - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - } - return StopperResult::kStopSuccess; - }); + // TODO: b/335934714 - Make sure the process actually exits + bool res = kill(proc->pid(), SIGINT) == 0; + return res ? StopperResult::kStopSuccess : StopperResult::kStopFailure; + })); const std::string crosvm_path = CF_EXPECT(CrosvmPathForVhostUserGpu(config)); @@ -312,6 +312,15 @@ Result<VhostUserDeviceCommands> BuildVhostUserGpu( // Connect device to main crosvm: gpu_device_cmd.Cmd().AddParameter("--socket=", gpu_device_socket_path); + + main_crosvm_cmd->AddPrerequisite([gpu_device_socket_path]() -> Result<void> { +#ifdef __linux__ + return WaitForUnixSocketListeningWithoutConnect(gpu_device_socket_path, + /*timeoutSec=*/30); +#else + return CF_ERR("Unhandled check if vhost user gpu ready."); +#endif + }); main_crosvm_cmd->AddParameter( "--vhost-user=gpu,pci-address=", gpu_pci_address, ",socket=", gpu_device_socket_path); @@ -379,6 +388,10 @@ Result<void> ConfigureGpu(const CuttlefishConfig& config, Command* crosvm_cmd) { crosvm_cmd->AddParameter( "--gpu=context-types=gfxstream-vulkan:gfxstream-composer", gpu_common_3d_string); + } else if (gpu_mode == kGpuModeCustom) { + const std::string gpu_context_types = + "--gpu=context-types=" + instance.gpu_context_types(); + crosvm_cmd->AddParameter(gpu_context_types, gpu_common_string); } MaybeConfigureVulkanIcd(config, crosvm_cmd); @@ -456,7 +469,9 @@ Result<std::vector<MonitorCommand>> CrosvmManager::StartCommands( // Disable USB passthrough. It isn't needed for any key use cases and it is // not compatible with crosvm suspend-resume support yet (b/266622743). // TODO: Allow it to be turned back on using a flag. - crosvm_cmd.Cmd().AddParameter("--no-usb"); + if (!instance.enable_usb()) { + crosvm_cmd.Cmd().AddParameter("--no-usb"); + } crosvm_cmd.Cmd().AddParameter("--core-scheduling=false"); @@ -669,17 +684,12 @@ Result<std::vector<MonitorCommand>> CrosvmManager::StartCommands( Command crosvm_log_tee_cmd(HostBinaryPath("log_tee")); crosvm_log_tee_cmd.AddParameter("--process_name=crosvm"); crosvm_log_tee_cmd.AddParameter("--log_fd_in=", crosvm_logs); - crosvm_log_tee_cmd.SetStopper([](Subprocess* proc) { + crosvm_log_tee_cmd.SetStopper(KillSubprocessFallback([](Subprocess* proc) { // Ask nicely so that log_tee gets a chance to process all the logs. - int rval = kill(proc->pid(), SIGINT); - if (rval != 0) { - LOG(ERROR) << "Failed to stop log_tee nicely, attempting to KILL"; - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - } - return StopperResult::kStopSuccess; - }); + bool res = kill(proc->pid(), SIGINT) == 0; + // TODO: b/335934714 - Make sure the process actually exits + return res ? StopperResult::kStopSuccess : StopperResult::kStopFailure; + })); // /dev/hvc2 = serial logging // Serial port for logcat, redirected to a pipe diff --git a/host/libs/vm_manager/gem5_manager.cpp b/host/libs/vm_manager/gem5_manager.cpp index df62785a2..79a5e4ba7 100644 --- a/host/libs/vm_manager/gem5_manager.cpp +++ b/host/libs/vm_manager/gem5_manager.cpp @@ -280,11 +280,6 @@ Result<std::vector<MonitorCommand>> Gem5Manager::StartCommands( const CuttlefishConfig& config, std::vector<VmmDependencyCommand*>&) { auto instance = config.ForDefaultInstance(); - auto stop = [](Subprocess* proc) { - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - }; std::string gem5_binary = instance.gem5_binary_dir(); switch (arch_) { case Arch::Arm: @@ -302,7 +297,7 @@ Result<std::vector<MonitorCommand>> Gem5Manager::StartCommands( // generate Gem5 starter_fs.py before we execute it GenerateGem5File(config, instance); - Command gem5_cmd(gem5_binary, stop); + Command gem5_cmd(gem5_binary); // Always enable listeners, because auto mode will disable once it detects // gem5 is not run interactively diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp index 38fead7b7..0f300d41d 100644 --- a/host/libs/vm_manager/qemu_manager.cpp +++ b/host/libs/vm_manager/qemu_manager.cpp @@ -51,7 +51,7 @@ std::string GetMonitorPath(const CuttlefishConfig& config) { "qemu_monitor.sock"); } -bool Stop() { +StopperResult Stop() { auto config = CuttlefishConfig::Get(); auto monitor_path = GetMonitorPath(*config); auto monitor_sock = SharedFD::SocketLocalClient( @@ -59,7 +59,7 @@ bool Stop() { if (!monitor_sock->IsOpen()) { LOG(ERROR) << "The connection to qemu is closed, is it still running?"; - return false; + return StopperResult::kStopFailure; } char msg[] = "{\"execute\":\"qmp_capabilities\"}{\"execute\":\"quit\"}"; ssize_t len = sizeof(msg) - 1; @@ -67,7 +67,7 @@ bool Stop() { int tmp = monitor_sock->Write(msg, len); if (tmp < 0) { LOG(ERROR) << "Error writing to socket: " << monitor_sock->StrError(); - return false; + return StopperResult::kStopFailure; } len -= tmp; } @@ -78,7 +78,7 @@ bool Stop() { LOG(INFO) << "From qemu monitor: " << buff; } - return true; + return StopperResult::kStopSuccess; } Result<std::pair<int, int>> GetQemuVersion(const std::string& qemu_binary) { @@ -216,18 +216,6 @@ QemuManager::ConfigureBootDevices( Result<std::vector<MonitorCommand>> QemuManager::StartCommands( const CuttlefishConfig& config, std::vector<VmmDependencyCommand*>&) { auto instance = config.ForDefaultInstance(); - - auto stop = [](Subprocess* proc) { - auto stopped = Stop(); - if (stopped) { - return StopperResult::kStopSuccess; - } - LOG(WARNING) << "Failed to stop VMM nicely, " - << "attempting to KILL"; - return KillSubprocess(proc) == StopperResult::kStopSuccess - ? StopperResult::kStopCrash - : StopperResult::kStopFailure; - }; std::string qemu_binary = instance.qemu_binary_dir(); switch (arch_) { case Arch::Arm: @@ -248,7 +236,7 @@ Result<std::vector<MonitorCommand>> QemuManager::StartCommands( } auto qemu_version = CF_EXPECT(GetQemuVersion(qemu_binary)); - Command qemu_cmd(qemu_binary, stop); + Command qemu_cmd(qemu_binary, KillSubprocessFallback(Stop)); int hvc_num = 0; int serial_num = 0; @@ -819,6 +807,9 @@ Result<std::vector<MonitorCommand>> QemuManager::StartCommands( qemu_cmd.AddParameter("-device"); qemu_cmd.AddParameter("qemu-xhci,id=xhci"); + qemu_cmd.AddParameter("-L"); + qemu_cmd.AddParameter(HostQemuBiosPath()); + if (is_riscv64) { qemu_cmd.AddParameter("-kernel"); } else { diff --git a/shared/chd/chd_debug.prop b/shared/chd/chd_debug.prop index 163a293b7..9e9de7abc 100644 --- a/shared/chd/chd_debug.prop +++ b/shared/chd/chd_debug.prop @@ -21,3 +21,6 @@ # Disable adb authentication to allow test automation for CHD. ro.adb.secure=0 + +# Allow 'adb root' on user build CHD +ro.debuggable=1 diff --git a/system_image/Android.bp b/system_image/Android.bp index fff8482bf..062ff2068 100644 --- a/system_image/Android.bp +++ b/system_image/Android.bp @@ -149,6 +149,7 @@ android_system_image { "bootanimation", "bootctl", "bootstat", + "boringssl_self_test", "bpfloader", "bu", "bugreport_procdump", @@ -187,6 +188,7 @@ android_system_image { "e2freefrag", "e2fsck", "e2fsdroid", + "etc_hosts", "evemu-record", "extra_free_kbytes", "fastbootd", @@ -230,6 +232,7 @@ android_system_image { "incident-helper-cmd", "incident", "incidentd", + "init-debug.rc", "init_first_stage", "init.boringssl.zygote64_32.rc", "init.boringssl.zygote64.rc", @@ -259,12 +262,14 @@ android_system_image { "libaaudio", "libadbd_auth", "libadbd_fs", + "libalarm_jni", "libamidi", "libandroid_runtime", "libandroid_servers", "libandroid", "libandroidemu", "libandroidfw", + "libartpalette-system", "libasyncio", "libasyncio", "libaudio_aidl_conversion_common_ndk_cpp", @@ -288,6 +293,7 @@ android_system_image { "libaudioutils", "libaudioutils", "libbinder_ndk", + "libbinder_rpc_unstable", "libbinder", "libblas", "libbootloader_message", @@ -351,6 +357,8 @@ android_system_image { "libhidcommand_jni", "libhidlmemory", "libhidlmemory", + "libhidltransport", + "libhwbinder", "libincident", "libinput", "libinputflinger", @@ -377,6 +385,7 @@ android_system_image { "libnetd_client", "libnetlink", "libnetutils", + "libneuralnetworks_packageinfo", "libnfc_nci_jni", "libnl", "libOpenglCodecCommon", @@ -423,6 +432,7 @@ android_system_image { "libsync", "libsysutils", "libtinyxml2", + "libtombstoned_client", "libtracingproxy", "libui", "libuinputcommand_jni", @@ -450,6 +460,7 @@ android_system_image { "logcatd", "logd", "logpersist.start", + "logtagd.rc", "logwrapper", "lpdump", "lpdumpd", @@ -457,6 +468,7 @@ android_system_image { "make_f2fs", "mapper.minigbm", "mdnsd", + "media_profiles_V1_0.dtd", "mediacodec.policy", "mediaextractor", "mediametrics", @@ -680,7 +692,6 @@ android_system_image { "ping", "ping6", "pintool", - "plat_sepolicy_and_mapping.sha256", "platform.xml", "pm", "power.default", @@ -691,6 +702,7 @@ android_system_image { "preinstalled-packages-platform-handheld-system.xml", "preinstalled-packages-platform-telephony-product.xml", "preinstalled-packages-platform.xml", + "preinstalled-packages-strict-signature.xml", "preloads_copy.sh", "preloads_copy.sh", "preopt2cachename", @@ -721,7 +733,6 @@ android_system_image { "screenrecord", "sdcard", "secdiscard", - "secilc", "sensorservice", "server_configurable_flags", "service", @@ -731,6 +742,7 @@ android_system_image { "settaskprofile", "settings", "sfdo", + "sgdisk", "sh", "showmap", "simpleperf_app_runner", @@ -803,38 +815,6 @@ android_system_image { "xml2abx", "xtables.lock", "ziptool", - // TODO(b/321000103): uncomment when visibility option for partitions is introduced - // "boringssl_self_test_vendor", - // "boringssl_self_test", - // "init_second_stage", - // "libaecsw", - // "libagc1sw", - // "libagc2sw", - // "libalarm_jni", - // "libartpalette-system", - // "libbassboostsw", - // "libbinder_rpc_unstable", - // "libbundleaidl", - // "libdownmixaidl", - // "libdynamicsprocessingaidl", - // "libenvreverbsw", - // "libequalizersw", - // "libextensioneffect", - // "libhapticgeneratoraidl", - // "libhidltransport", - // "libhwbinder", - // "libloudnessenhanceraidl", - // "libmdnssd", - // "libmediametrics", - // "libneuralnetworks_packageinfo", - // "libnssw", - // "libpreprocessingaidl", - // "libpresetreverbsw", - // "libreverbaidl", - // "libvirtualizersw", - // "libvisualizeraidl", - // "libvolumesw", - // "sgdisk", ], multilib: { common: { @@ -850,6 +830,7 @@ android_system_image { "androidx.camera.extensions.impl", "androidx.window.extensions", "androidx.window.sidecar", + "aosp_mainline_modules", "BackupRestoreConfirmation", "BasicDreams", "BlockedNumberProvider", @@ -872,15 +853,9 @@ android_system_image { "CertInstaller", "CFSatelliteService", "charger_res_images", - "com.android.adbd", - "com.android.adservices", "com.android.apex.cts.shim.v1_prebuilt", - "com.android.appsearch", "com.android.cellbroadcast", "com.android.compos", - "com.android.configinfrastructure", - "com.android.devicelock", - "com.android.extservices", "com.android.future.usb.accessory", "com.android.hardware.authsecret", "com.android.hardware.biometrics.face.virtual", @@ -891,6 +866,8 @@ android_system_image { "com.android.hardware.dumpstate", "com.android.hardware.gnss", "com.android.hardware.input.processor", + "com.android.hardware.keymint.rust_cf_remote", + "com.android.hardware.keymint.rust_nonsecure", "com.android.hardware.memtrack", "com.android.hardware.net.nlinterceptor", "com.android.hardware.neuralnetworks", @@ -915,20 +892,9 @@ android_system_image { "com.android.location.provider", "com.android.media.remotedisplay.xml", "com.android.media.remotedisplay", - "com.android.media.swcodec", - "com.android.media", "com.android.mediadrm.signer", - "com.android.mediaprovider", - "com.android.neuralnetworks", "com.android.nfc_extras", - "com.android.os.statsd", - "com.android.resolv", - "com.android.rkpd", "com.android.runtime", - "com.android.scheduling", - "com.android.tethering", - "com.android.tzdata", - "com.android.virt", "com.google.cf.bt", "com.google.cf.confirmationui", "com.google.cf.health.storage", @@ -961,7 +927,9 @@ android_system_image { "ExternalStorageProvider", "ExtShared", "framework-graphics", + "framework-location", "framework-minus-apex-install-dependencies", + "framework-nfc", "framework-res", "FusedLocation", "fuseMedia.o", @@ -982,6 +950,7 @@ android_system_image { "LiveWallpapersPicker", "llndk.libraries.txt", "LocalTransport", + "lockagent", "ManagedProvisioning", "MediaProviderLegacy", "messaging", @@ -998,14 +967,6 @@ android_system_image { "PacProcessor", "PartnerBookmarksProvider", "PhotoTable", - "plat_file_contexts", - "plat_hwservice_contexts", - "plat_keystore2_key_contexts", - "plat_mapping_file", - "plat_property_contexts", - "plat_seapp_contexts", - "plat_sepolicy.cil", - "plat_service_contexts", "PrintRecommendationService", "PrintSpooler", "Provision", @@ -1013,6 +974,7 @@ android_system_image { "QualifiedNetworksService", "QuickSearchBox", "SecureElement", + "selinux_policy_system_soong", "services", "Settings", "SettingsIntelligence", @@ -1035,36 +997,24 @@ android_system_image { "TeleService", "timeInState.o", "Traceur", - "userdebug_plat_sepolicy.cil", "UserDictionaryProvider", "voip-common", "VpnDialogs", "WallpaperBackup", "WallpaperCropper", "webview", - // TODO(b/321000103): uncomment when visibility option for partitions is introduced - // "com.android.art", - // "com.android.btservices", - // "com.android.conscrypt", - // "com.android.healthfitness", - // "com.android.ondevicepersonalization", - // "com.android.permission", - // "com.android.sdkext", - // "com.android.uwb", - // "framework-minus-apex", ], }, lib32: { deps: [ "android.hardware.audio.service", - "mediaserver", "drmserver", + "mediaserver", ], }, lib64: { deps: [ - // TODO(b/321000103): uncomment when visibility option for partitions is introduced - // "boringssl_self_test", + "boringssl_self_test", "libgsi", "servicemanager", ], diff --git a/tests/snapshot/OWNERS b/tests/snapshot/OWNERS new file mode 100644 index 000000000..671026eed --- /dev/null +++ b/tests/snapshot/OWNERS @@ -0,0 +1,3 @@ +fmayle@google.com +khei@google.com +smoreland@google.com diff --git a/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java b/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java index 19b36ecda..d1e071c4f 100644 --- a/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java +++ b/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java @@ -44,7 +44,7 @@ public class SnapshotTest extends BaseHostJUnit4Test { @Option( name = "test-count", description = "Number of times to restore the device back to snapshot state.") - private int mTestCount = 1; + private int mTestCount = 10; @Test public void testSnapshot() throws Exception { diff --git a/tests/wmediumd_control/Android.bp b/tests/wmediumd_control/Android.bp index e23cf2921..e62321b32 100644 --- a/tests/wmediumd_control/Android.bp +++ b/tests/wmediumd_control/Android.bp @@ -35,5 +35,6 @@ java_test_host { "cuttlefish_host_test_utils", "platform-test-annotations", "WmediumdServerProto_java", + "libprotobuf-java-util-full", ], } diff --git a/tools/launch_cvd_arm64_server_docker.sh b/tools/launch_cvd_arm64_server_docker.sh index 7979cddd6..ac1a9392c 100755 --- a/tools/launch_cvd_arm64_server_docker.sh +++ b/tools/launch_cvd_arm64_server_docker.sh @@ -140,6 +140,19 @@ ssh $server \ done" echo -e "Done" +# extract cvd-host_package.tar.gz with /:extract API if the API exists +ssh $server \ + "job_id=\$(curl -s -k -X POST ${host_orchestrator_url}/userartifacts/$user_artifacts_dir/cvd-host_package.tar.gz/:extract | jq -r '.name' 2>/dev/null) && \ + if [[ \$job_id != \"\" ]]; then \ + echo Extracting cvd-host_package.tar.gz ... && \ + job_done=\"false\" && \ + while [[ \$job_done == \"false\" ]]; do \ + sleep 1 && \ + job_done=\$(curl -s -k ${host_orchestrator_url}/operations/\$job_id | jq -r '.done'); \ + done && \ + echo Done; \ + fi" + echo -e "Creating image from root docker container" root_image_id=$(ssh $server -t "docker commit $root_container_id cvd_root_image:$root_container_id") root_image_id=${root_image_id//$'\r'} # to remove trailing ^M |