From a47f7575d182a3691b38c7d64fd82486ba97188d Mon Sep 17 00:00:00 2001 From: Chad Reynolds Date: Mon, 2 Mar 2026 15:04:31 -0800 Subject: [PATCH 01/52] Add test for branch fetches fixed by PR 2160 To verify the behavior is not broken with future fetch or zip handling updates. Bug: 476141347 --- e2etests/cvd/launch_cvd_tests/main_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/e2etests/cvd/launch_cvd_tests/main_test.go b/e2etests/cvd/launch_cvd_tests/main_test.go index d2d0e6c5bec..fcaa89db5d2 100644 --- a/e2etests/cvd/launch_cvd_tests/main_test.go +++ b/e2etests/cvd/launch_cvd_tests/main_test.go @@ -61,6 +61,11 @@ func TestLaunchCvd(t *testing.T) { branch: "git_android16-car-release", target: "aosp_cf_x86_64_auto-userdebug", }, + { + name: "Aosp11GsiPhone", + branch: "aosp-android11-gsi", + target: "aosp_cf_x86_64_only_phone-userdebug", + }, } c := e2etests.TestContext{} for _, tc := range testcases { From 75cb366ed0d310a25c0d2486dff89cd9f01d43cc Mon Sep 17 00:00:00 2001 From: My Name Date: Fri, 12 Jun 2026 10:01:14 +0000 Subject: [PATCH 02/52] Update cvd start to handle single instances --- .../commands/cvd/cli/commands/BUILD.bazel | 1 + .../host/commands/cvd/cli/commands/start.cpp | 99 +++++++++++++++++++ .../host/commands/cvd/cli/commands/start.h | 4 + 3 files changed, 104 insertions(+) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel index 22da76db6bc..d21df5bf69d 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/BUILD.bazel @@ -390,6 +390,7 @@ cf_cc_library( hdrs = ["start.h"], clang_format_enabled = False, deps = [ + "//cuttlefish/common/libs/fs", "//cuttlefish/common/libs/utils:contains", "//cuttlefish/common/libs/utils:files", "//cuttlefish/common/libs/utils:json", diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp index 66b686663bf..21c3d47bbd1 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp @@ -16,6 +16,7 @@ #include "cuttlefish/host/commands/cvd/cli/commands/start.h" +#include #include // IWYU pragma: keep #include #include @@ -41,6 +42,7 @@ #include "absl/strings/str_join.h" #include "absl/strings/str_split.h" +#include "cuttlefish/common/libs/fs/shared_fd.h" #include "cuttlefish/common/libs/utils/contains.h" #include "cuttlefish/common/libs/utils/files.h" #include "cuttlefish/flag_parser/flag.h" @@ -328,6 +330,21 @@ static Result ConsumeDaemonModeFlag(cvd_common::Args& args) { return {}; } +static bool HasUnsafeFlagsForBypass(const std::vector& args) { + std::vector args_copy = args; + bool daemon = true; + std::string report_anonymous = ""; + std::vector safe_flags = { + GflagsCompatFlag("daemon", daemon), + GflagsCompatFlag("report_anonymous_usage_stats", report_anonymous), + }; + auto res = ConsumeFlags(safe_flags, args_copy); + if (!res.ok()) { + return true; + } + return !args_copy.empty(); +} + Result CvdStartCommandHandler::Handle(const CommandRequest& request) { std::vector subcmd_args = request.SubcommandArguments(); CF_EXPECT(!GetConfigPath(subcmd_args).has_value(), @@ -338,6 +355,22 @@ Result CvdStartCommandHandler::Handle(const CommandRequest& request) { return CF_ERR(NoGroupMessage(request)); } + if (request.Selectors().instance_names && + request.Selectors().instance_names->size() == 1) { + auto [instance, group] = + CF_EXPECT(selector::SelectInstance(instance_manager_, request)); + + if (instance.State() == cvd::INSTANCE_STATE_STOPPED && + group.StartTime() != TimeStamp{} && + !HasUnsafeFlagsForBypass(subcmd_args)) { + CF_EXPECT(LaunchSingleInstance(instance, group, request)); + return {}; + } else { + VLOG(1) << "Instance is not in stopped state. Proceeding with " + "normal group start."; + } + } + CF_EXPECT(ConsumeDaemonModeFlag(subcmd_args)); subcmd_args.push_back("--daemon=true"); @@ -495,6 +528,72 @@ Result CvdStartCommandHandler::LaunchDeviceInterruptible( return {}; } +Result CvdStartCommandHandler::LaunchSingleInstance( + LocalInstance& instance, LocalInstanceGroup& group, + const CommandRequest& request) { + auto bin_path = group.HostArtifactsPath() + "/bin/run_cvd"; + cvd_common::Envs run_cvd_envs = request.Env(); + run_cvd_envs[kCuttlefishInstanceEnvVarName] = std::to_string(instance.Id()); + run_cvd_envs["HOME"] = group.HomeDir(); + run_cvd_envs[kAndroidHostOut] = group.HostArtifactsPath(); + run_cvd_envs[kAndroidProductOut] = group.ProductOutPath(); + run_cvd_envs[kAndroidSoongHostOut] = group.HostArtifactsPath(); + run_cvd_envs[kCvdMarkEnv] = "true"; + + ConstructCommandParam construct_cmd_param{.bin_path = bin_path, + .home = group.HomeDir(), + .args = cvd_common::Args{}, + .envs = run_cvd_envs, + .working_dir = CurrentDirectory(), + .command_name = "run_cvd"}; + + Command command = CF_EXPECT(ConstructCommand(construct_cmd_param)); + command.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, + Subprocess::StdIOChannel::kStdErr); + SharedFD dev_null = SharedFD::Open("/dev/null", O_RDONLY); + if (dev_null->IsOpen()) { + command.RedirectStdIO(Subprocess::StdIOChannel::kStdIn, dev_null); + } else { + LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError(); + } + + auto symlink_config_res = SymlinkPreviousConfig(group.HomeDir()); + if (!symlink_config_res.ok()) { + LOG(ERROR) << "Failed to symlink the config file at system wide home: " + << symlink_config_res.error(); + } + + auto set_instance_state = [&group, &instance](cvd::InstanceState state) { + for (auto& inst : group.Instances()) { + if (inst.Id() == instance.Id()) { + inst.SetState(state); + break; + } + } + }; + + set_instance_state(cvd::INSTANCE_STATE_STARTING); + group.SetStartTime(CvdServerClock::now()); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + + Result start_res = + LaunchDevice(std::move(command), group, run_cvd_envs, request); + + if (!start_res.ok()) { + set_instance_state(cvd::INSTANCE_STATE_BOOT_FAILED); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + return start_res; + } + + set_instance_state(cvd::INSTANCE_STATE_RUNNING); + CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); + + auto group_json = CF_EXPECT(group.FetchStatus()); + std::cout << group_json.toStyledString(); + + return {}; +} + std::vector CvdStartCommandHandler::Description() const { std::vector description; description.emplace_back( diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h index 6b836cb0078..6479ce40088 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.h @@ -43,6 +43,10 @@ class CvdStartCommandHandler : public CvdCommandHandler { bool RequiresDeviceExists() const override { return true; } private: + Result LaunchSingleInstance(LocalInstance& instance, + LocalInstanceGroup& group, + const CommandRequest& request); + Result LaunchDevice(Command command, LocalInstanceGroup& group, const cvd_common::Envs& envs, const CommandRequest& request); From 2505ccc6a9ed9623afa04a01c409d3daf28474f6 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Mon, 15 Jun 2026 17:12:10 -0400 Subject: [PATCH 03/52] Use anonymous namespace. --- base/cvd/cuttlefish/common/libs/utils/container.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/base/cvd/cuttlefish/common/libs/utils/container.cpp b/base/cvd/cuttlefish/common/libs/utils/container.cpp index 0425edff373..f9fba2a822d 100644 --- a/base/cvd/cuttlefish/common/libs/utils/container.cpp +++ b/base/cvd/cuttlefish/common/libs/utils/container.cpp @@ -22,15 +22,16 @@ #include "cuttlefish/common/libs/utils/files.h" namespace cuttlefish { +namespace { -static bool IsRunningInDocker() { +bool IsRunningInDocker() { // if /.dockerenv exists, it's inside a docker container - static std::string docker_env_path("/.dockerenv"); - static bool ret = - FileExists(docker_env_path) || DirectoryExists(docker_env_path); - return ret; + std::string docker_env_path("/.dockerenv"); + return FileExists(docker_env_path) || DirectoryExists(docker_env_path); } +} // namespace + bool IsRunningInContainer() { // TODO: add more if we support other containers than docker return IsRunningInDocker(); From a8a4ef05fecf7dc5104db184d1e118802f907405 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Mon, 15 Jun 2026 17:18:31 -0400 Subject: [PATCH 04/52] Detect podman container environment. Bug: b/523379344 --- base/cvd/cuttlefish/common/libs/utils/container.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/base/cvd/cuttlefish/common/libs/utils/container.cpp b/base/cvd/cuttlefish/common/libs/utils/container.cpp index f9fba2a822d..91896508b7b 100644 --- a/base/cvd/cuttlefish/common/libs/utils/container.cpp +++ b/base/cvd/cuttlefish/common/libs/utils/container.cpp @@ -30,11 +30,13 @@ bool IsRunningInDocker() { return FileExists(docker_env_path) || DirectoryExists(docker_env_path); } +bool IsRunningInPodman() { return FileExists("/run/.containerenv"); } + } // namespace bool IsRunningInContainer() { // TODO: add more if we support other containers than docker - return IsRunningInDocker(); + return IsRunningInDocker() || IsRunningInPodman(); } } // namespace cuttlefish From 109273907fdca499c9dc26302000d615b79f5c0c Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Mon, 15 Jun 2026 18:21:27 -0400 Subject: [PATCH 05/52] `cvd start` now works after cvd detects is in container environment. - `enable_sandbox` is calculated dynamically on second `cvd start`, true if running directly in the host, false if running in a container. As `cvd` wasn't detecting podman container environments yet, it assumed it was running directly in the host defaulting to enable_sandbox to true which fails if running in a container. Bug: b/523379344 --- .../stop_start_test/main_test.go | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/e2etests/orchestration/stop_start_test/main_test.go b/e2etests/orchestration/stop_start_test/main_test.go index ed4ade7d152..ad1e6116858 100644 --- a/e2etests/orchestration/stop_start_test/main_test.go +++ b/e2etests/orchestration/stop_start_test/main_test.go @@ -104,17 +104,16 @@ func TestStopStart(t *testing.T) { t.Fatalf("status mismatch (-want +got):\n%s", diff) } - // TODO(b/523379344): Failing to boot. - // if err := srv.StartGroup("cvd_1", &hoapi.StartCVDRequest{}); err != nil { - // t.Fatal(err) - // } - // cvds, err = srv.ListCVDs() - // if err != nil { - // t.Fatal(err) - // } - // if diff := cmp.Diff(cvdStatus(cvds), []string{"Running", "Running"}); diff != "" { - // t.Fatalf("status mismatch (-want +got):\n%s", diff) - // } + if err := srv.StartGroup("cvd_1", &hoapi.StartCVDRequest{}); err != nil { + t.Fatal(err) + } + cvds, err = srv.ListCVDs() + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(cvdStatus(cvds), []string{"Running", "Running"}); diff != "" { + t.Fatalf("status mismatch (-want +got):\n%s", diff) + } } func cvdStatus(cvds []*hoapi.CVD) []string { From bc216290c5a71d186e90f7ef27a7baad0121fe8b Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Mon, 15 Jun 2026 19:14:03 -0400 Subject: [PATCH 06/52] HO snapshot e2e tests passes now. HO snapshot e2e tests passes now after `enable_sandbox` is properly handled when running in a podman container. Bug: b/517984573 --- .../commands/cvd/cli/parser/instance/cf_vm_configs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp index 181707a67ff..8f9f0d10b64 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp @@ -257,10 +257,10 @@ Result> GenerateVmFlags( if (used_names.contains(kFlagUuid)) { flags.push_back(GenerateInstanceFlag(kFlagUuid, cfg, Uuid)); } - // TODO(b/517984573): Always pass enable_sandbox. - // if (used_names.contains(kFlagEnableSandbox)) { - flags.push_back(GenerateInstanceFlag(kFlagEnableSandbox, cfg, EnableSandbox)); - // } + if (used_names.contains(kFlagEnableSandbox)) { + flags.push_back( + GenerateInstanceFlag(kFlagEnableSandbox, cfg, EnableSandbox)); + } if (used_names.contains(kFlagCrosvmSimpleMediaDevice)) { flags.push_back(GenerateInstanceFlag(kFlagCrosvmSimpleMediaDevice, cfg, SimpleMediaDevice)); From 5a0be3e9c6452784968f3c17076bc7591e88ada9 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 18 Jun 2026 15:30:32 -0700 Subject: [PATCH 07/52] Delete the AospMainX64PhoneX2 test This is currently failing only on internal kokoro Bug: b/525526391 --- e2etests/cvd/cvd_load_tests/main_test.go | 26 ------------------------ 1 file changed, 26 deletions(-) diff --git a/e2etests/cvd/cvd_load_tests/main_test.go b/e2etests/cvd/cvd_load_tests/main_test.go index 7ca46517d49..646ccfb76b9 100644 --- a/e2etests/cvd/cvd_load_tests/main_test.go +++ b/e2etests/cvd/cvd_load_tests/main_test.go @@ -107,32 +107,6 @@ func TestCvdLoad(t *testing.T) { "common": { "host_package": "@ab\/aosp-android-latest-release\/aosp_cf_x86_64_only_phone-userdebug" } -}`, - }, - { - name: "AospMainX64PhoneX2", - loadconfig: ` -{ - "instances": [ - { - "name": "ins-1", - "disk": { - "default_build": "@ab\/aosp-android-latest-release\/aosp_cf_x86_64_only_phone-userdebug" - } - }, - { - "name": "ins-2", - "disk": { - "default_build": "@ab\/aosp-android-latest-release\/aosp_cf_x86_64_only_phone-userdebug" - } - } - ], - "metrics": { - "enable": true - }, - "common": { - "host_package": "@ab\/aosp-android-latest-release\/aosp_cf_x86_64_only_phone-userdebug" - } }`, }, } From a4ce08845789fbafc7bfa3d73d83670d4fa32238 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 18 Jun 2026 08:45:57 -0700 Subject: [PATCH 08/52] Split vulkan check into vulkan loader and vulkan driver checks Bug: b/525390484 Test: `cvd create` and inspect launcher.log --- .../commands/assemble_cvd/graphics_flags.cc | 33 +++++++++++------ .../host/graphics_detector/BUILD.bazel | 2 ++ .../graphics_detector/graphics_detector.cpp | 2 ++ .../graphics_detector/graphics_detector.proto | 2 ++ .../graphics_detector_vk_loader.cpp | 35 +++++++++++++++++++ .../graphics_detector_vk_loader.h | 26 ++++++++++++++ 6 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.cpp create mode 100644 base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index 84ce67848e5..b4a8aac7d91 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -177,18 +177,29 @@ GetGpuModeRequirementsMap() { "Consider enabling --gpu_mode=gfxstream_guest_angle_host_swiftshader " "for host software rendering which has a vetted software renderer.", }; - // TODO: separate host vulkan loader check out. - const RequirementWithReason kHostVulkanAvailable{ + const RequirementWithReason kHostVulkanLoaderAvailable{ + .func = + [](const CommonState& common) { + const auto& availability = common.graphics_availability; + return availability.vulkan_loader_available(); + }, + .success_explanation = + "The host has the Vulkan loader installed and " + "available.", + .failure_explanation = + "The host does not have the Vulkan loader installed. Please ensure " + "the Vulkan loader is installed and available.", + }; + const RequirementWithReason kHostVulkanDriverAvailable{ .func = [](const CommonState& common) { const auto& availability = common.graphics_availability; return availability.has_vulkan(); }, - .success_explanation = "The host has Vulkan support.", + .success_explanation = "The host has a Vulkan driver available.", .failure_explanation = - "The host does not have Vulkan support. Please ensure the Vulkan " - "userspace drivers and the Vulkan loader are installed and " - "available.", + "The host does not have a Vulkan driver available. Please ensure " + "a Vulkan driver is installed.", }; const RequirementWithReason kHostVulkanIsNonSoftwareRenderer{ .func = @@ -252,7 +263,8 @@ GetGpuModeRequirementsMap() { kHostGlesAvailable, kHostGlesIsNonSoftwareRenderer, kHostIsNonArm, - kHostVulkanAvailable, + kHostVulkanLoaderAvailable, + kHostVulkanDriverAvailable, kHostVulkanIsNonSoftwareRenderer, }, }, @@ -261,7 +273,8 @@ GetGpuModeRequirementsMap() { { kGuestSupportsGfxstream, kHostIsNonArm, - kHostVulkanAvailable, + kHostVulkanLoaderAvailable, + kHostVulkanDriverAvailable, kHostVulkanIsNonSoftwareRenderer, kHostVulkanMemoryCanBeMappedIntoKvm, kNotUsingHostQemu, @@ -272,7 +285,7 @@ GetGpuModeRequirementsMap() { { kGuestSupportsGfxstream, kHostIsNonArm, - kHostVulkanAvailable, + kHostVulkanLoaderAvailable, kNotUsingHostQemu, }, }, @@ -281,7 +294,7 @@ GetGpuModeRequirementsMap() { { kGuestSupportsGfxstream, kHostIsNonArm, - kHostVulkanAvailable, + kHostVulkanLoaderAvailable, kNotUsingHostQemu, }, }, diff --git a/base/cvd/cuttlefish/host/graphics_detector/BUILD.bazel b/base/cvd/cuttlefish/host/graphics_detector/BUILD.bazel index 871bf41f1cf..08a88bc0b46 100644 --- a/base/cvd/cuttlefish/host/graphics_detector/BUILD.bazel +++ b/base/cvd/cuttlefish/host/graphics_detector/BUILD.bazel @@ -35,6 +35,8 @@ cf_cc_binary( "graphics_detector_vk.h", "graphics_detector_vk_external_memory_host.cpp", "graphics_detector_vk_external_memory_host.h", + "graphics_detector_vk_loader.cpp", + "graphics_detector_vk_loader.h", "graphics_detector_vk_precision_qualifiers_on_yuv_samplers.cpp", "graphics_detector_vk_precision_qualifiers_on_yuv_samplers.h", "image.cpp", diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.cpp b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.cpp index c4849ece40d..b6dd36c1114 100644 --- a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.cpp +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.cpp @@ -19,6 +19,7 @@ #include "cuttlefish/host/graphics_detector/graphics_detector_gl.h" #include "cuttlefish/host/graphics_detector/graphics_detector_vk.h" #include "cuttlefish/host/graphics_detector/graphics_detector_vk_external_memory_host.h" +#include "cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h" #include "cuttlefish/host/graphics_detector/graphics_detector_vk_precision_qualifiers_on_yuv_samplers.h" #include "cuttlefish/host/graphics_detector/subprocess.h" @@ -32,6 +33,7 @@ ::gfxstream::proto::GraphicsAvailability DetectGraphicsAvailability() { const std::vector> checks = { {"PopulateEglAndGlesAvailability", PopulateEglAndGlesAvailability}, {"PopulateVulkanAvailability", PopulateVulkanAvailability}, + {"PopulateVulkanLoaderAvailability", PopulateVulkanLoaderAvailability}, {"PopulateVulkanExternalMemoryHostQuirk", PopulateVulkanExternalMemoryHostQuirk}, {"PopulateVulkanPrecisionQualifiersOnYuvSamplersQuirk", diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto index 0858b58c25d..dcbfdd40955 100644 --- a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto @@ -76,4 +76,6 @@ message GraphicsAvailability { optional VulkanAvailability vulkan = 2; repeated string errors = 3; + + optional bool vulkan_loader_available = 4; } diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.cpp b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.cpp new file mode 100644 index 00000000000..9175c586bf2 --- /dev/null +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h" + +#include + +#include "cuttlefish/host/graphics_detector/expected.h" + +namespace gfxstream { + +gfxstream::expected PopulateVulkanLoaderAvailability( + ::gfxstream::proto::GraphicsAvailability* availability) { + void* libvulkan = dlopen("libvulkan.so.1", RTLD_LAZY | RTLD_LOCAL); + availability->set_vulkan_loader_available(libvulkan != nullptr); + if (libvulkan) { + dlclose(libvulkan); + } + return Ok{}; +} + +} // namespace gfxstream diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h new file mode 100644 index 00000000000..586a41dcc85 --- /dev/null +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk_loader.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "cuttlefish/host/graphics_detector/expected.h" +#include "cuttlefish/host/graphics_detector/graphics_detector.pb.h" + +namespace gfxstream { + +gfxstream::expected PopulateVulkanLoaderAvailability( + ::gfxstream::proto::GraphicsAvailability* availability); + +} // namespace gfxstream From b621b6315f4b57d6618432ead600be06b0edc529 Mon Sep 17 00:00:00 2001 From: JaeMan Park Date: Wed, 17 Jun 2026 14:26:32 +0900 Subject: [PATCH 09/52] Add vhost_user_vsock support for cvd load configuration Since vhost_user_vsock is not enabled by default at x86_64, we need to turn it on manually to support multiple docker instance scenario. But there is a no way to set it by using Host Orchestrator API. So add support for vhost_user_vsock to cvd load configuration file that can be used for Host Orchestrator API. --- .../cvd/cli/parser/instance/cf_vm_configs.cpp | 16 +++++ .../cli/parser/instance/vm_configs_test.cc | 67 +++++++++++++++++++ .../commands/cvd/cli/parser/load_config.proto | 1 + 3 files changed, 84 insertions(+) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp index 8f9f0d10b64..fbd3cee10bf 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_vm_configs.cpp @@ -49,6 +49,7 @@ inline constexpr char kFlagEnableSandbox[] = "enable_sandbox"; inline constexpr char kFlagCrosvmSimpleMediaDevice[] = "crosvm_simple_media_device"; inline constexpr char kFlagCrosvmV4l2Proxy[] = "crosvm_v4l2_proxy"; +inline constexpr char kFlagVhostUserVsock[] = "vhost_user_vsock"; inline constexpr char kFlagEnablePkvm[] = "enable_pkvm"; std::set GatherFlagNamesUsedInInstanceConfig(const Instance& ins) { @@ -83,6 +84,10 @@ std::set GatherFlagNamesUsedInInstanceConfig(const Instance& ins) { ins.vm().crosvm().has_v4l2_proxy()) { names.insert(kFlagCrosvmV4l2Proxy); } + if (ins.vm().vmm_case() == Vm::VmmCase::kCrosvm && + ins.vm().crosvm().has_vhost_user_vsock()) { + names.insert(kFlagVhostUserVsock); + } if (ins.vm().has_enable_pkvm()) { names.insert(kFlagEnablePkvm); } @@ -179,6 +184,13 @@ static std::string V4l2Proxy(const Instance& instance) { return crosvm.has_v4l2_proxy() ? crosvm.v4l2_proxy() : default_val; } +static std::string VhostUserVsock(const Instance& instance) { + const auto& crosvm = instance.vm().crosvm(); + const auto& default_val = CF_DEFAULTS_VHOST_USER_VSOCK; + return crosvm.has_vhost_user_vsock() ? crosvm.vhost_user_vsock() + : default_val; +} + static bool EnablePkvm(const Instance& instance) { const auto& vm = instance.vm(); return vm.has_enable_pkvm() ? vm.enable_pkvm() : CF_DEFAULTS_ENABLE_PKVM; @@ -269,6 +281,10 @@ Result> GenerateVmFlags( flags.emplace_back( GenerateInstanceFlag(kFlagCrosvmV4l2Proxy, cfg, V4l2Proxy)); } + if (used_names.contains(kFlagVhostUserVsock)) { + flags.emplace_back( + GenerateInstanceFlag(kFlagVhostUserVsock, cfg, VhostUserVsock)); + } if (used_names.contains(kFlagEnablePkvm)) { flags.emplace_back(GenerateInstanceFlag(kFlagEnablePkvm, cfg, EnablePkvm)); } diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/vm_configs_test.cc b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/vm_configs_test.cc index 9401a4bde5d..6d90077e89d 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/vm_configs_test.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/vm_configs_test.cc @@ -743,4 +743,71 @@ TEST(VmFlagsParserTest, ParseTwoInstancesCustomActionsFlagPartialJson) { EXPECT_THAT(ParseJson(custom_actions[0]), IsOkAndValue(expected_actions)); } +TEST(VmFlagsParserTest, ParseTwoInstancesVhostUserVsockFlagPartialJson) { + const char* test_string = R""""( +{ + "instances" : + [ + { + "vm": { + "crosvm":{ + } + } + }, + { + "vm": { + "crosvm":{ + "vhost_user_vsock": "true" + } + } + } + ] +} + )""""; + + Json::Value json_configs; + std::string json_text(test_string); + + EXPECT_TRUE(ParseJsonString(json_text, json_configs)) + << "Invalid Json string"; + auto serialized_data = LaunchCvdParserTester(json_configs); + EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); + EXPECT_TRUE(FindConfig(*serialized_data, R"(--vhost_user_vsock=auto,true)")) + << "vhost_user_vsock flag is missing or wrongly formatted"; +} + +TEST(VmFlagsParserTest, ParseTwoInstancesVhostUserVsockFlagFullJson) { + const char* test_string = R""""( +{ + "instances" : + [ + { + "vm": { + "crosvm":{ + "vhost_user_vsock": "true" + } + } + }, + { + "vm": { + "crosvm":{ + "vhost_user_vsock": "false" + } + } + } + ] +} + )""""; + + Json::Value json_configs; + std::string json_text(test_string); + + EXPECT_TRUE(ParseJsonString(json_text, json_configs)) + << "Invalid Json string"; + auto serialized_data = LaunchCvdParserTester(json_configs); + EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); + EXPECT_TRUE(FindConfig(*serialized_data, R"(--vhost_user_vsock=true,false)")) + << "vhost_user_vsock flag is missing or wrongly formatted"; +} + } // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/load_config.proto b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/load_config.proto index a9177160a87..c80696c2b72 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/load_config.proto +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/load_config.proto @@ -199,6 +199,7 @@ message Crosvm { optional bool enable_sandbox = 1; optional bool simple_media_device = 2; optional string v4l2_proxy = 3; + optional string vhost_user_vsock = 4; } message Gem5 {} From f45cb05cc396c60d0d80818435412654171a2d44 Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Thu, 25 Jun 2026 18:53:36 +0000 Subject: [PATCH 10/52] Support v4l2_emulated_camera_mplane in media e2etests Bug: b/527958719 Test: `bazel build //cvd/media_tests:media_tests` --- e2etests/cvd/media_tests/main_test.go | 17 ++++++++++++----- e2etests/debian_substitution_marker | 5 +++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/e2etests/cvd/media_tests/main_test.go b/e2etests/cvd/media_tests/main_test.go index eb14d63fb39..95351062a36 100644 --- a/e2etests/cvd/media_tests/main_test.go +++ b/e2etests/cvd/media_tests/main_test.go @@ -23,12 +23,19 @@ import ( func TestEmulatedCameraV4l2Compliance(t *testing.T) { testcases := []struct { - branch string - target string + branch string + target string + mediaType string }{ { - branch: "git_main", - target: "aosp_cf_x86_64_only_phone-trunk_staging-userdebug", + branch: "git_main", + target: "aosp_cf_x86_64_only_phone-trunk_staging-userdebug", + mediaType: "v4l2_emulated_camera_splane", + }, + { + branch: "git_main-throttled-nightly", + target: "aosp_cf_x86_64_auto-trunk_staging-userdebug", + mediaType: "v4l2_emulated_camera_mplane", }, } c := e2etests.TestContext{} @@ -44,7 +51,7 @@ func TestEmulatedCameraV4l2Compliance(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{Args: []string{"--media=type=v4l2_emulated_camera_splane"}}); err != nil { + if err := c.CVDCreate(e2etests.CreateArgs{Args: []string{fmt.Sprintf("--media=type=%s", tc.mediaType)}}); err != nil { t.Fatal(err) } diff --git a/e2etests/debian_substitution_marker b/e2etests/debian_substitution_marker index 83c485fcbfb..2d08e12467a 100644 --- a/e2etests/debian_substitution_marker +++ b/e2etests/debian_substitution_marker @@ -220,6 +220,11 @@ symlinks: { link_name: "bin/vhu_media_emulated_camera_splane" } +symlinks: { + target: "/usr/lib/cuttlefish-common/bin/vhu_media_emulated_camera_mplane" + link_name: "bin/vhu_media_emulated_camera_mplane" +} + symlinks: { target: "/usr/lib/cuttlefish-common/bin/webRTC" link_name: "bin/webRTC" From 3236c0e39832aa89094aae5620da917ae7152930 Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Wed, 8 Jul 2026 10:05:01 +0000 Subject: [PATCH 11/52] Add required_ab tags on Kokoro tests --- e2etests/cvd/cvd_create_tests/BUILD.bazel | 2 ++ e2etests/cvd/cvd_load_tests/BUILD.bazel | 1 + e2etests/cvd/graphics_tests/gfxstream/BUILD.bazel | 1 + e2etests/cvd/graphics_tests/gfxstream_guest_angle/BUILD.bazel | 1 + .../gfxstream_guest_angle_host_swiftshader/BUILD.bazel | 1 + e2etests/cvd/launch_cvd_tests/BUILD.bazel | 1 + e2etests/cvd/logs_tests/BUILD.bazel | 1 + e2etests/cvd/media_tests/BUILD.bazel | 1 + e2etests/cvd/networking_tests/BUILD.bazel | 1 + 9 files changed, 10 insertions(+) diff --git a/e2etests/cvd/cvd_create_tests/BUILD.bazel b/e2etests/cvd/cvd_create_tests/BUILD.bazel index cac31215791..5d9544addfa 100644 --- a/e2etests/cvd/cvd_create_tests/BUILD.bazel +++ b/e2etests/cvd/cvd_create_tests/BUILD.bazel @@ -22,6 +22,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], deps = [ @@ -39,6 +40,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], deps = [ diff --git a/e2etests/cvd/cvd_load_tests/BUILD.bazel b/e2etests/cvd/cvd_load_tests/BUILD.bazel index a9343065be5..b08ed7faad1 100644 --- a/e2etests/cvd/cvd_load_tests/BUILD.bazel +++ b/e2etests/cvd/cvd_load_tests/BUILD.bazel @@ -25,6 +25,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], ) diff --git a/e2etests/cvd/graphics_tests/gfxstream/BUILD.bazel b/e2etests/cvd/graphics_tests/gfxstream/BUILD.bazel index e538b962439..f883f688c17 100644 --- a/e2etests/cvd/graphics_tests/gfxstream/BUILD.bazel +++ b/e2etests/cvd/graphics_tests/gfxstream/BUILD.bazel @@ -25,6 +25,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "requires_gpu", "supports-graceful-termination", ], diff --git a/e2etests/cvd/graphics_tests/gfxstream_guest_angle/BUILD.bazel b/e2etests/cvd/graphics_tests/gfxstream_guest_angle/BUILD.bazel index 6c8dfec34ca..989db29d357 100644 --- a/e2etests/cvd/graphics_tests/gfxstream_guest_angle/BUILD.bazel +++ b/e2etests/cvd/graphics_tests/gfxstream_guest_angle/BUILD.bazel @@ -25,6 +25,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", # This does not actually require a GPU but currently only the GPU image # has the XTS requirements preinstalled. "requires_gpu", diff --git a/e2etests/cvd/graphics_tests/gfxstream_guest_angle_host_swiftshader/BUILD.bazel b/e2etests/cvd/graphics_tests/gfxstream_guest_angle_host_swiftshader/BUILD.bazel index c77acb18d9e..52d976174b5 100644 --- a/e2etests/cvd/graphics_tests/gfxstream_guest_angle_host_swiftshader/BUILD.bazel +++ b/e2etests/cvd/graphics_tests/gfxstream_guest_angle_host_swiftshader/BUILD.bazel @@ -25,6 +25,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], ) diff --git a/e2etests/cvd/launch_cvd_tests/BUILD.bazel b/e2etests/cvd/launch_cvd_tests/BUILD.bazel index 4a38cc20ca2..2b95748fdf0 100644 --- a/e2etests/cvd/launch_cvd_tests/BUILD.bazel +++ b/e2etests/cvd/launch_cvd_tests/BUILD.bazel @@ -25,6 +25,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], ) diff --git a/e2etests/cvd/logs_tests/BUILD.bazel b/e2etests/cvd/logs_tests/BUILD.bazel index 1bf7c8b0653..880b0135d42 100644 --- a/e2etests/cvd/logs_tests/BUILD.bazel +++ b/e2etests/cvd/logs_tests/BUILD.bazel @@ -10,6 +10,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], deps = [ diff --git a/e2etests/cvd/media_tests/BUILD.bazel b/e2etests/cvd/media_tests/BUILD.bazel index 26581384dcb..8ae8f33fabf 100644 --- a/e2etests/cvd/media_tests/BUILD.bazel +++ b/e2etests/cvd/media_tests/BUILD.bazel @@ -24,6 +24,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], deps = [ diff --git a/e2etests/cvd/networking_tests/BUILD.bazel b/e2etests/cvd/networking_tests/BUILD.bazel index 016558d0542..07f6b17475c 100644 --- a/e2etests/cvd/networking_tests/BUILD.bazel +++ b/e2etests/cvd/networking_tests/BUILD.bazel @@ -13,6 +13,7 @@ go_test( "exclusive", "external", "no-sandbox", + "requires_ab", "supports-graceful-termination", ], deps = [ From 7aad4595173f6f6706f1075abc8dfbda9d005272 Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Wed, 8 Jul 2026 10:10:24 +0000 Subject: [PATCH 12/52] Disable all Kokoro test cases which requires ab --- tools/testutils/runcvde2etests.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testutils/runcvde2etests.sh b/tools/testutils/runcvde2etests.sh index 6d674b6da5e..eeb06ae4533 100755 --- a/tools/testutils/runcvde2etests.sh +++ b/tools/testutils/runcvde2etests.sh @@ -23,6 +23,10 @@ while getopts "g" opt; do esac done +# TODO(b/532409657): Disable all test cases requiring ab for a moment as +# they're not working. +bazel_test_tag_filter_arg+=",-requires_ab" + function gather_test_results() { # Don't immediately exit on error anymore set +e From 39df2f333f50752eefae7f943fe7af1830806e04 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Thu, 9 Jul 2026 14:41:28 -0400 Subject: [PATCH 13/52] Install `aapt` in container image used for running e2e tests. - `aapt` is required to run CTS tests. Bug: b/502639876 --- tools/testutils/cw/Containerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/testutils/cw/Containerfile b/tools/testutils/cw/Containerfile index 3dee19c77d2..e0afd83c939 100644 --- a/tools/testutils/cw/Containerfile +++ b/tools/testutils/cw/Containerfile @@ -6,6 +6,9 @@ ENV OVERRIDE_BAZEL_WRAPPER_DOWNLOAD_DIR=/tmp/cw_bazel RUN apt-get update && apt-get upgrade -y RUN apt-get install -y sudo systemd init systemd-journal-remote nginx jq adb +# Packages needed to run CTS +RUN apt-get install -y aapt + RUN groupadd kvm COPY tools/testutils/cw/setup.service /etc/systemd/system/setup.service RUN systemctl enable setup From 54204102b800c9c9bc649b8f4a2ea89bcc8f6fe8 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Wed, 8 Jul 2026 15:51:10 -0400 Subject: [PATCH 14/52] Move v4l2 compliance test into its own directory. Bug: b/502639876 --- e2etests/cvd/media_tests/BUILD.bazel | 20 ----------- .../media_tests/v4l2compliance/BUILD.bazel | 33 +++++++++++++++++++ .../{ => v4l2compliance}/main_test.go | 0 3 files changed, 33 insertions(+), 20 deletions(-) create mode 100644 e2etests/cvd/media_tests/v4l2compliance/BUILD.bazel rename e2etests/cvd/media_tests/{ => v4l2compliance}/main_test.go (100%) diff --git a/e2etests/cvd/media_tests/BUILD.bazel b/e2etests/cvd/media_tests/BUILD.bazel index 8ae8f33fabf..9703a09f39c 100644 --- a/e2etests/cvd/media_tests/BUILD.bazel +++ b/e2etests/cvd/media_tests/BUILD.bazel @@ -11,23 +11,3 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -load("@rules_go//go:def.bzl", "go_test") - -go_test( - name = "media_tests", - size = "large", - srcs = ["main_test.go"], - data = ["//:debian_substitution_marker"], - env = {"LOCAL_DEBIAN_SUBSTITUTION_MARKER_FILE": "$(rlocationpath //:debian_substitution_marker)"}, - tags = [ - "exclusive", - "external", - "no-sandbox", - "requires_ab", - "supports-graceful-termination", - ], - deps = [ - "//cvd/common", - ], -) diff --git a/e2etests/cvd/media_tests/v4l2compliance/BUILD.bazel b/e2etests/cvd/media_tests/v4l2compliance/BUILD.bazel new file mode 100644 index 00000000000..8ae8f33fabf --- /dev/null +++ b/e2etests/cvd/media_tests/v4l2compliance/BUILD.bazel @@ -0,0 +1,33 @@ +# Copyright (C) 2026 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_go//go:def.bzl", "go_test") + +go_test( + name = "media_tests", + size = "large", + srcs = ["main_test.go"], + data = ["//:debian_substitution_marker"], + env = {"LOCAL_DEBIAN_SUBSTITUTION_MARKER_FILE": "$(rlocationpath //:debian_substitution_marker)"}, + tags = [ + "exclusive", + "external", + "no-sandbox", + "requires_ab", + "supports-graceful-termination", + ], + deps = [ + "//cvd/common", + ], +) diff --git a/e2etests/cvd/media_tests/main_test.go b/e2etests/cvd/media_tests/v4l2compliance/main_test.go similarity index 100% rename from e2etests/cvd/media_tests/main_test.go rename to e2etests/cvd/media_tests/v4l2compliance/main_test.go From d9268a211f05e74ad7aba56e2241bf433c9718e1 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Thu, 9 Jul 2026 14:34:21 -0400 Subject: [PATCH 15/52] Use CTS tests for verifying new emulated cameras devices. - Start with android.app.cts.SystemFeaturesTest#testCameraFeatures Bug: b/502639876 --- e2etests/cvd/media_tests/cts/BUILD.bazel | 31 ++++++++++++++++ e2etests/cvd/media_tests/cts/main_test.go | 45 +++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 e2etests/cvd/media_tests/cts/BUILD.bazel create mode 100644 e2etests/cvd/media_tests/cts/main_test.go diff --git a/e2etests/cvd/media_tests/cts/BUILD.bazel b/e2etests/cvd/media_tests/cts/BUILD.bazel new file mode 100644 index 00000000000..9babc7e7c95 --- /dev/null +++ b/e2etests/cvd/media_tests/cts/BUILD.bazel @@ -0,0 +1,31 @@ +# Copyright (C) 2026 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_go//go:def.bzl", "go_test") + +go_test( + name = "media_tests", + srcs = ["main_test.go"], + deps = [ + "//cvd/common:common", + ], + size = "large", + tags = [ + "exclusive", + "external", + "no-sandbox", + "requires_ab", + "supports-graceful-termination", + ], +) diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go new file mode 100644 index 00000000000..4d0ddb3792e --- /dev/null +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -0,0 +1,45 @@ +// Copyright (C) 2026 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "testing" + + "github.com/google/android-cuttlefish/e2etests/cvd/common" +) + +func TestEmulatedCamera(t *testing.T) { + e2etests.RunXts(t, + e2etests.FetchAndCreateArgs{ + Fetch: e2etests.FetchArgs{ + DefaultBuildBranch: "git_main", + DefaultBuildTarget: "aosp_cf_x86_64_only_phone-trunk_staging-userdebug", + TestSuiteBuildBranch: "aosp-android15-tests-release", + TestSuiteBuildTarget: "test_suites_x86_64", + }, + Create: e2etests.CreateArgs{ + Args: []string{ + "--media=type=v4l2_emulated_camera_splane,lens_facing=BACK", + "--media=type=v4l2_emulated_camera_splane,lens_facing=FRONT", + }, + }, + }, + e2etests.XtsArgs{ + XtsType: "cts", + XtsArgs: []string{ + "--include-filter=CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures", + }, + }) +} From d1e1effe993340709198385d030fb8d48fc64d0c Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Tue, 30 Jun 2026 16:48:02 +0000 Subject: [PATCH 16/52] e2etests/cvd: add basic testing for sdv Bug: b/507906785 Test: bazel build --- e2etests/cvd/cvd_create_tests/main_test.go | 8 +++ e2etests/cvd/cvd_load_tests/main_test.go | 59 ++++++++++++++++++++++ e2etests/cvd/launch_cvd_tests/main_test.go | 15 ++++++ 3 files changed, 82 insertions(+) diff --git a/e2etests/cvd/cvd_create_tests/main_test.go b/e2etests/cvd/cvd_create_tests/main_test.go index 36ad9da854b..174189aa922 100644 --- a/e2etests/cvd/cvd_create_tests/main_test.go +++ b/e2etests/cvd/cvd_create_tests/main_test.go @@ -38,6 +38,14 @@ func TestCvdCreate(t *testing.T) { branch: "git_main-throttled-nightly", target: "aosp_cf_x86_64_auto-trunk_staging-userdebug", }, + { + branch: "git_main-swcar-dev", + target: "aosp_cf_x86_64_sdv_core-trunk_staging-userdebug", + }, + { + branch: "git_main-swcar-dev", + target: "aosp_cf_x86_64_sdv_media-trunk_staging-userdebug", + }, } c := e2etests.TestContext{} for _, tc := range testcases { diff --git a/e2etests/cvd/cvd_load_tests/main_test.go b/e2etests/cvd/cvd_load_tests/main_test.go index 646ccfb76b9..69612f98721 100644 --- a/e2etests/cvd/cvd_load_tests/main_test.go +++ b/e2etests/cvd/cvd_load_tests/main_test.go @@ -107,6 +107,65 @@ func TestCvdLoad(t *testing.T) { "common": { "host_package": "@ab\/aosp-android-latest-release\/aosp_cf_x86_64_only_phone-userdebug" } +}`, + }, + { + name: "GitSwCarDevSdv", + loadconfig: ` +{ + "instances": [ + { + "name": "ins-1", + "vm": { + "cpus": 2, + "memory_mb": 2048 + }, + "boot": { + "extra_bootconfig_args": "androidboot.sdv.instance_name=instance1 androidboot.virt.address=3 androidboot.sdv.boot_mode=unlocked" + }, + "security": { + "guest_enforce_security": false + }, + "disk": { + "default_build": "@ab\/git_main-swcar-dev\/aosp_cf_x86_64_sdv_core-trunk_staging-userdebug" + }, + "graphics": { + "gpu_mode": "none" + } + }, + { + "name": "ins-2", + "vm": { + "cpus": 4, + "memory_mb": 4096 + }, + "boot": { + "extra_bootconfig_args": "androidboot.sdv.instance_name=instance2 androidboot.virt.address=4 androidboot.sdv.boot_mode=unlocked" + }, + "security": { + "guest_enforce_security": false + }, + "disk": { + "default_build": "@ab\/git_main-swcar-dev\/aosp_cf_x86_64_sdv_media-trunk_staging-userdebug" + }, + "graphics": { + "displays": [ + { + "width": 1920, + "height": 1080 + } + ], + "gpu_mode": "gfxstream_guest_angle_host_swiftshader" + } + } + ], + "netsim_bt": false, + "metrics": { + "enable": true + }, + "common": { + "host_package": "@ab\/git_main-swcar-dev\/aosp_cf_x86_64_sdv_media-trunk_staging-userdebug" + } }`, }, } diff --git a/e2etests/cvd/launch_cvd_tests/main_test.go b/e2etests/cvd/launch_cvd_tests/main_test.go index fcaa89db5d2..d5d874d55e4 100644 --- a/e2etests/cvd/launch_cvd_tests/main_test.go +++ b/e2etests/cvd/launch_cvd_tests/main_test.go @@ -61,6 +61,21 @@ func TestLaunchCvd(t *testing.T) { branch: "git_android16-car-release", target: "aosp_cf_x86_64_auto-userdebug", }, + { + name: "Car17Auto", + branch: "git_android17-car-release", + target: "aosp_cf_x86_64_auto-userdebug", + }, + { + name: "GitSwCarDevSdvCore", + branch: "git_main-swcar-dev", + target: "aosp_cf_x86_64_sdv_core-trunk_staging-userdebug", + }, + { + name: "GitSwCarDevSdvMedia", + branch: "git_main-swcar-dev", + target: "aosp_cf_x86_64_sdv_media-trunk_staging-userdebug", + }, { name: "Aosp11GsiPhone", branch: "aosp-android11-gsi", From 98cd5cb28286b6de9c70f1e97a653f2ca483e30c Mon Sep 17 00:00:00 2001 From: Arjun Dhaliwal Date: Thu, 9 Jul 2026 19:23:40 -0700 Subject: [PATCH 17/52] Add networking test case for cvdalloc --- e2etests/cvd/networking_tests/main_test.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/e2etests/cvd/networking_tests/main_test.go b/e2etests/cvd/networking_tests/main_test.go index 29923ed3668..fa01ade2c62 100644 --- a/e2etests/cvd/networking_tests/main_test.go +++ b/e2etests/cvd/networking_tests/main_test.go @@ -25,8 +25,10 @@ import ( func TestDeviceNetworking(t *testing.T) { testcases := []struct { - branch string - target string + name string + branch string + target string + createArgs e2etests.CreateArgs }{ { branch: "aosp-android-latest-release", @@ -36,10 +38,22 @@ func TestDeviceNetworking(t *testing.T) { branch: "git_main", target: "aosp_cf_x86_64_only_phone-trunk_staging-userdebug", }, + { + name: "cvdalloc", + branch: "git_main", + target: "aosp_cf_x86_64_only_phone-trunk_staging-userdebug", + createArgs: e2etests.CreateArgs{ + Args: []string{"--use_cvdalloc=true"}, + }, + }, } c := e2etests.TestContext{} for _, tc := range testcases { - t.Run(fmt.Sprintf("BUILD=%s/%s", tc.branch, tc.target), func(t *testing.T) { + testName := fmt.Sprintf("BUILD=%s/%s", tc.branch, tc.target) + if tc.name != "" { + testName = fmt.Sprintf("%s_CONFIG=%s", testName, tc.name) + } + t.Run(testName, func(t *testing.T) { c.SetUp(t) defer c.TearDown() @@ -52,7 +66,7 @@ func TestDeviceNetworking(t *testing.T) { } t.Log("Launching Cuttlefish...") - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if err := c.CVDCreate(tc.createArgs); err != nil { t.Fatal(err) } From 048007b5c982ef8cb53f8c7fab7feb1a44e211e3 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Wed, 15 Jul 2026 14:31:00 -0400 Subject: [PATCH 18/52] Use v4l2_emulated_camera_mplane in cts test. v4l2_emulated_camera_mplane is the actual device would be used in production. Bug: b/533512719 --- e2etests/cvd/media_tests/cts/main_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go index 4d0ddb3792e..fc1e80d0a8d 100644 --- a/e2etests/cvd/media_tests/cts/main_test.go +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -31,8 +31,8 @@ func TestEmulatedCamera(t *testing.T) { }, Create: e2etests.CreateArgs{ Args: []string{ - "--media=type=v4l2_emulated_camera_splane,lens_facing=BACK", - "--media=type=v4l2_emulated_camera_splane,lens_facing=FRONT", + "--media=type=v4l2_emulated_camera_mplane,lens_facing=BACK", + "--media=type=v4l2_emulated_camera_mplane,lens_facing=FRONT", }, }, }, From 914ff5f3e82952f16edbaa0cf986136187a7def2 Mon Sep 17 00:00:00 2001 From: My Name Date: Thu, 2 Jul 2026 12:13:13 +0000 Subject: [PATCH 19/52] improve the LaunchSingleInstance bypass in cvd start --- .../host/commands/cvd/cli/commands/start.cpp | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp index 21c3d47bbd1..39f5e53f3c5 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/commands/start.cpp @@ -312,6 +312,41 @@ Result> GetCvdInternalStartFlags( return flags; } +bool CanBypassToSingleInstance(const LocalInstance& instance, + const LocalInstanceGroup& group, + const std::vector& subcmd_args) { + if (instance.State() != cvd::INSTANCE_STATE_STOPPED) { + return false; + } + if (group.StartTime() == TimeStamp{}) { + return false; + } + + std::vector args_copy = subcmd_args; + bool daemon = true; + std::vector safe_flags = { + GflagsCompatFlag("daemon", daemon), + }; + const Result res = ConsumeFlags(safe_flags, args_copy); + if (!res.ok() || !daemon || !args_copy.empty()) { + return false; + } + + const std::vector& instances = group.Instances(); + if (instances.empty()) { + return false; + } + const LocalInstance& main_instance = instances[0]; + if (instance.Id() == main_instance.Id()) { + return false; + } + if (main_instance.State() != cvd::INSTANCE_STATE_RUNNING) { + return false; + } + + return true; +} + } // namespace CvdStartCommandHandler::CvdStartCommandHandler( @@ -330,21 +365,6 @@ static Result ConsumeDaemonModeFlag(cvd_common::Args& args) { return {}; } -static bool HasUnsafeFlagsForBypass(const std::vector& args) { - std::vector args_copy = args; - bool daemon = true; - std::string report_anonymous = ""; - std::vector safe_flags = { - GflagsCompatFlag("daemon", daemon), - GflagsCompatFlag("report_anonymous_usage_stats", report_anonymous), - }; - auto res = ConsumeFlags(safe_flags, args_copy); - if (!res.ok()) { - return true; - } - return !args_copy.empty(); -} - Result CvdStartCommandHandler::Handle(const CommandRequest& request) { std::vector subcmd_args = request.SubcommandArguments(); CF_EXPECT(!GetConfigPath(subcmd_args).has_value(), @@ -360,13 +380,11 @@ Result CvdStartCommandHandler::Handle(const CommandRequest& request) { auto [instance, group] = CF_EXPECT(selector::SelectInstance(instance_manager_, request)); - if (instance.State() == cvd::INSTANCE_STATE_STOPPED && - group.StartTime() != TimeStamp{} && - !HasUnsafeFlagsForBypass(subcmd_args)) { + if (CanBypassToSingleInstance(instance, group, subcmd_args)) { CF_EXPECT(LaunchSingleInstance(instance, group, request)); return {}; } else { - VLOG(1) << "Instance is not in stopped state. Proceeding with " + VLOG(1) << "Cannot bypass to single instance start. Proceeding with " "normal group start."; } } @@ -531,7 +549,7 @@ Result CvdStartCommandHandler::LaunchDeviceInterruptible( Result CvdStartCommandHandler::LaunchSingleInstance( LocalInstance& instance, LocalInstanceGroup& group, const CommandRequest& request) { - auto bin_path = group.HostArtifactsPath() + "/bin/run_cvd"; + const std::string bin_path = group.HostArtifactsPath() + "/bin/run_cvd"; cvd_common::Envs run_cvd_envs = request.Env(); run_cvd_envs[kCuttlefishInstanceEnvVarName] = std::to_string(instance.Id()); run_cvd_envs["HOME"] = group.HomeDir(); @@ -557,7 +575,8 @@ Result CvdStartCommandHandler::LaunchSingleInstance( LOG(ERROR) << "Failed to open /dev/null: " << dev_null->StrError(); } - auto symlink_config_res = SymlinkPreviousConfig(group.HomeDir()); + const Result symlink_config_res = + SymlinkPreviousConfig(group.HomeDir()); if (!symlink_config_res.ok()) { LOG(ERROR) << "Failed to symlink the config file at system wide home: " << symlink_config_res.error(); @@ -588,7 +607,7 @@ Result CvdStartCommandHandler::LaunchSingleInstance( set_instance_state(cvd::INSTANCE_STATE_RUNNING); CF_EXPECT(instance_manager_.UpdateInstanceGroup(group)); - auto group_json = CF_EXPECT(group.FetchStatus()); + const Json::Value group_json = CF_EXPECT(group.FetchStatus()); std::cout << group_json.toStyledString(); return {}; From 26b490d25085dc0d1d1bb0d157810941bd5c2d23 Mon Sep 17 00:00:00 2001 From: Sarah Kim Date: Mon, 20 Jul 2026 18:15:32 -0700 Subject: [PATCH 20/52] #VibeCoding Support AT+CEID and AT+CATR in modem simulator Implement custom AT commands AT+CEID and AT+CATR in the modem simulator to expose the EID and ATR values configured in the simulated SIM profile (XML). This allows the radio HAL to query these values dynamically instead of hardcoding them, supporting eSIM slot detection. BUG=532745689 --- .../etc/files/iccprofile_for_sim0.xml | 6 +- ...le_for_sim0_for_CtsCarrierApiTestCases.xml | 6 +- .../commands/modem_simulator/sim_service.cpp | 58 +++++++++++++++++++ .../commands/modem_simulator/sim_service.h | 2 + 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0.xml b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0.xml index 655c37a967a..25ad8495b39 100755 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0.xml +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0.xml @@ -177,5 +177,9 @@ - + + + 3F979580BFFE8210428031A073BE211797 + 89049032000001000000000254806852 + diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml index b4363da9308..1b65eb621a4 100755 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml @@ -203,5 +203,9 @@ - + + + 3F979580BFFE8210428031A073BE211797 + 89049032000001000000000254806852 + diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.cpp index 0d5f7646fd4..46f4d802781 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.cpp @@ -313,6 +313,12 @@ std::vector SimService::InitializeCommandHandlers() { CommandHandler( "+CICCID", [this](const Client& client) { this->HandleGetIccId(client); }), + CommandHandler( + "+CEID", + [this](const Client& client) { this->HandleGetEid(client); }), + CommandHandler( + "+CATR", + [this](const Client& client) { this->HandleGetAtr(client); }), CommandHandler("+CLCK=", [this](const Client& client, std::string& cmd) { this->HandleFacilityLock(client, cmd); @@ -1323,6 +1329,58 @@ void SimService::HandleGetIccId(const Client& client) { client.SendCommandResponse(responses); } +void SimService::HandleGetEid(const Client& client) { + std::vector responses; + + XMLElement* root = sim_file_system_.GetRootElement(); + if (!root) { + client.SendCommandResponse(kCmeErrorOperationNotAllowed); + return; + } + + XMLElement* card_profile = root->FirstChildElement("CardProfile"); + if (!card_profile) { + client.SendCommandResponse(kCmeErrorNotFound); + return; + } + + XMLElement* final = card_profile->FirstChildElement("EID"); + if (!final) { + client.SendCommandResponse(kCmeErrorNotFound); + return; + } + + responses.push_back("+CEID: " + std::string(final->GetText())); + responses.push_back("OK"); + client.SendCommandResponse(responses); +} + +void SimService::HandleGetAtr(const Client& client) { + std::vector responses; + + XMLElement* root = sim_file_system_.GetRootElement(); + if (!root) { + client.SendCommandResponse(kCmeErrorOperationNotAllowed); + return; + } + + XMLElement* card_profile = root->FirstChildElement("CardProfile"); + if (!card_profile) { + client.SendCommandResponse(kCmeErrorNotFound); + return; + } + + XMLElement* final = card_profile->FirstChildElement("ATR"); + if (!final) { + client.SendCommandResponse(kCmeErrorNotFound); + return; + } + + responses.push_back("+CATR: " + std::string(final->GetText())); + responses.push_back("OK"); + client.SendCommandResponse(responses); +} + /* * AT+CLCK * Execute command is used to lock, unlock or interrogate a MT or a network diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.h b/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.h index 198aa697bfb..e3695f7791f 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.h +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/sim_service.h @@ -42,6 +42,8 @@ class SimService : public ModemService, public std::enable_shared_from_this Date: Wed, 22 Jul 2026 07:46:10 -0700 Subject: [PATCH 21/52] Update graphics detector to populate queue family info ... as this is needed to decide whether or not to emulate multiple queues in Gfxstream. Bug: b/537569893 Test: bazel run //cuttlefish/package:cvd -- create --- .../host/graphics_detector/graphics_detector.proto | 9 +++++++++ .../host/graphics_detector/graphics_detector_vk.cpp | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto index dcbfdd40955..e434f3e438e 100644 --- a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector.proto @@ -53,6 +53,13 @@ message VulkanQuirks { optional VulkanExternalMemoryHostQuirks external_memory_host_quirks = 2; } +message VulkanQueueFamily { + optional bool supports_compute = 1; + optional bool supports_graphics = 2; + optional bool supports_transfer = 3; + optional uint32 queue_count = 4; +} + message VulkanPhysicalDevice { optional string name = 1; repeated string extensions = 2; @@ -63,6 +70,8 @@ message VulkanPhysicalDevice { optional Type type = 3; optional VulkanQuirks quirks = 4; + + repeated VulkanQueueFamily queue_families = 5; } message VulkanAvailability { diff --git a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk.cpp b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk.cpp index f62950f871f..bf0a5b57211 100644 --- a/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk.cpp +++ b/base/cvd/cuttlefish/host/graphics_detector/graphics_detector_vk.cpp @@ -45,6 +45,18 @@ gfxstream::expected PopulateVulkanAvailabilityImpl( for (const auto& ext : exts) { outPhysicalDevice->add_extensions(std::string(ext.extensionName)); } + + const auto queueFamilies = physicalDevice.getQueueFamilyProperties(); + for (const auto& queueFamily : queueFamilies) { + auto* outQueueFamily = outPhysicalDevice->add_queue_families(); + outQueueFamily->set_supports_compute(static_cast( + queueFamily.queueFlags & vk::QueueFlagBits::eCompute)); + outQueueFamily->set_supports_graphics(static_cast( + queueFamily.queueFlags & vk::QueueFlagBits::eGraphics)); + outQueueFamily->set_supports_transfer(static_cast( + queueFamily.queueFlags & vk::QueueFlagBits::eTransfer)); + outQueueFamily->set_queue_count(queueFamily.queueCount); + } } return Ok{}; From 321a09063528883c7ddccaffa667fa37394a97d1 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 23 Jul 2026 09:12:17 -0700 Subject: [PATCH 22/52] Return CommandOutput from CVDFetch --- e2etests/cvd/bugreport_tests/main_test.go | 2 +- e2etests/cvd/common/common.go | 11 ++++++----- e2etests/cvd/cvd_create_tests/main_test.go | 2 +- e2etests/cvd/cvd_powerwash_tests/main_test.go | 2 +- e2etests/cvd/display_tests/main_test.go | 4 ++-- e2etests/cvd/env_tests/main_test.go | 2 +- e2etests/cvd/graphics_detector_tests/main_test.go | 2 +- e2etests/cvd/launch_cvd_tests/main_test.go | 2 +- e2etests/cvd/media_tests/v4l2compliance/main_test.go | 2 +- e2etests/cvd/metrics_tests/main_test.go | 2 +- e2etests/cvd/networking_tests/main_test.go | 2 +- 11 files changed, 17 insertions(+), 16 deletions(-) diff --git a/e2etests/cvd/bugreport_tests/main_test.go b/e2etests/cvd/bugreport_tests/main_test.go index a1d9c5d02c0..23b3c9d3c39 100644 --- a/e2etests/cvd/bugreport_tests/main_test.go +++ b/e2etests/cvd/bugreport_tests/main_test.go @@ -29,7 +29,7 @@ func TestTakeBugreport(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { diff --git a/e2etests/cvd/common/common.go b/e2etests/cvd/common/common.go index c827da9a8e9..e853efdc72c 100644 --- a/e2etests/cvd/common/common.go +++ b/e2etests/cvd/common/common.go @@ -166,7 +166,7 @@ type FetchAndCreateArgs struct { } // Performs `cvd fetch `. -func (tc *TestContext) CVDFetch(args FetchArgs) error { +func (tc *TestContext) CVDFetch(args FetchArgs) (CommandOutput, error) { log.Printf("Fetching...") fetchCmd := []string{ tc.TargetBin(), @@ -182,9 +182,10 @@ func (tc *TestContext) CVDFetch(args FetchArgs) error { if credentialArg != "" { fetchCmd = append(fetchCmd, fmt.Sprintf("--credential_source=%s", credentialArg)) } - if _, err := tc.RunCmd(fetchCmd...); err != nil { + res, err := tc.RunCmd(fetchCmd...); + if err != nil { log.Printf("Failed to fetch: %w", err) - return err + return res, err } // Android CTS includes some files with a `kernel` suffix which confuses the @@ -195,7 +196,7 @@ func (tc *TestContext) CVDFetch(args FetchArgs) error { log.Printf("Fetch completed!") - return nil + return res, nil } // Performs `cvd create `. @@ -577,7 +578,7 @@ func RunXts(t *testing.T, cuttlefishArgs FetchAndCreateArgs, xtsArgs XtsArgs) { log.Printf("Failed to find existing XTS, will fetch.") } - if err := tc.CVDFetch(cuttlefishArgs.Fetch); err != nil { + if _, err := tc.CVDFetch(cuttlefishArgs.Fetch); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/cvd_create_tests/main_test.go b/e2etests/cvd/cvd_create_tests/main_test.go index 174189aa922..326c0f9b4b7 100644 --- a/e2etests/cvd/cvd_create_tests/main_test.go +++ b/e2etests/cvd/cvd_create_tests/main_test.go @@ -53,7 +53,7 @@ func TestCvdCreate(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: tc.branch, DefaultBuildTarget: tc.target, }); err != nil { diff --git a/e2etests/cvd/cvd_powerwash_tests/main_test.go b/e2etests/cvd/cvd_powerwash_tests/main_test.go index e5161ab00ed..81a34bb3bbf 100644 --- a/e2etests/cvd/cvd_powerwash_tests/main_test.go +++ b/e2etests/cvd/cvd_powerwash_tests/main_test.go @@ -37,7 +37,7 @@ func TestCvdPowerwash(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: tc.branch, DefaultBuildTarget: tc.target, }); err != nil { diff --git a/e2etests/cvd/display_tests/main_test.go b/e2etests/cvd/display_tests/main_test.go index be15878fa4f..3cf4bbabed5 100644 --- a/e2etests/cvd/display_tests/main_test.go +++ b/e2etests/cvd/display_tests/main_test.go @@ -24,7 +24,7 @@ func addDisplay(c e2etests.TestContext, t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { @@ -44,7 +44,7 @@ func listDisplays(c e2etests.TestContext, t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { diff --git a/e2etests/cvd/env_tests/main_test.go b/e2etests/cvd/env_tests/main_test.go index d304e256b90..e1f4a6ab293 100644 --- a/e2etests/cvd/env_tests/main_test.go +++ b/e2etests/cvd/env_tests/main_test.go @@ -25,7 +25,7 @@ func TestListEnvServices(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { diff --git a/e2etests/cvd/graphics_detector_tests/main_test.go b/e2etests/cvd/graphics_detector_tests/main_test.go index 3cffec9a4b6..76aeb193075 100644 --- a/e2etests/cvd/graphics_detector_tests/main_test.go +++ b/e2etests/cvd/graphics_detector_tests/main_test.go @@ -25,7 +25,7 @@ func TestLaunchingWithAutoEnablesGfxstream(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { diff --git a/e2etests/cvd/launch_cvd_tests/main_test.go b/e2etests/cvd/launch_cvd_tests/main_test.go index d5d874d55e4..2df6625b79b 100644 --- a/e2etests/cvd/launch_cvd_tests/main_test.go +++ b/e2etests/cvd/launch_cvd_tests/main_test.go @@ -88,7 +88,7 @@ func TestLaunchCvd(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: tc.branch, DefaultBuildTarget: tc.target, }); err != nil { diff --git a/e2etests/cvd/media_tests/v4l2compliance/main_test.go b/e2etests/cvd/media_tests/v4l2compliance/main_test.go index 95351062a36..f5f1dbc612f 100644 --- a/e2etests/cvd/media_tests/v4l2compliance/main_test.go +++ b/e2etests/cvd/media_tests/v4l2compliance/main_test.go @@ -44,7 +44,7 @@ func TestEmulatedCameraV4l2Compliance(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: tc.branch, DefaultBuildTarget: tc.target, }); err != nil { diff --git a/e2etests/cvd/metrics_tests/main_test.go b/e2etests/cvd/metrics_tests/main_test.go index 59b6741a824..a6b25caf0df 100644 --- a/e2etests/cvd/metrics_tests/main_test.go +++ b/e2etests/cvd/metrics_tests/main_test.go @@ -37,7 +37,7 @@ func TestMetrics(t *testing.T) { c.SetUp(t) defer c.TearDown() - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { diff --git a/e2etests/cvd/networking_tests/main_test.go b/e2etests/cvd/networking_tests/main_test.go index fa01ade2c62..719f6595017 100644 --- a/e2etests/cvd/networking_tests/main_test.go +++ b/e2etests/cvd/networking_tests/main_test.go @@ -58,7 +58,7 @@ func TestDeviceNetworking(t *testing.T) { defer c.TearDown() t.Log("Fetching remote build...") - if err := c.CVDFetch(e2etests.FetchArgs{ + if _, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: tc.branch, DefaultBuildTarget: tc.target, }); err != nil { From f191b561348e7ace66291e4a2ba0651921288b36 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 23 Jul 2026 09:16:35 -0700 Subject: [PATCH 23/52] Return CommandOutput from CVDCreate --- e2etests/cvd/bugreport_tests/main_test.go | 2 +- e2etests/cvd/common/common.go | 11 ++++++----- e2etests/cvd/cvd_create_tests/main_test.go | 2 +- e2etests/cvd/cvd_powerwash_tests/main_test.go | 2 +- e2etests/cvd/display_tests/main_test.go | 8 ++++---- e2etests/cvd/env_tests/main_test.go | 2 +- e2etests/cvd/graphics_detector_tests/main_test.go | 2 +- e2etests/cvd/media_tests/v4l2compliance/main_test.go | 6 +++++- e2etests/cvd/metrics_tests/main_test.go | 2 +- e2etests/cvd/networking_tests/main_test.go | 2 +- 10 files changed, 22 insertions(+), 17 deletions(-) diff --git a/e2etests/cvd/bugreport_tests/main_test.go b/e2etests/cvd/bugreport_tests/main_test.go index 23b3c9d3c39..170b397d8bb 100644 --- a/e2etests/cvd/bugreport_tests/main_test.go +++ b/e2etests/cvd/bugreport_tests/main_test.go @@ -35,7 +35,7 @@ func TestTakeBugreport(t *testing.T) { }); err != nil { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/common/common.go b/e2etests/cvd/common/common.go index e853efdc72c..dd8af8b41c9 100644 --- a/e2etests/cvd/common/common.go +++ b/e2etests/cvd/common/common.go @@ -200,7 +200,7 @@ func (tc *TestContext) CVDFetch(args FetchArgs) (CommandOutput, error) { } // Performs `cvd create `. -func (tc *TestContext) CVDCreate(args CreateArgs) error { +func (tc *TestContext) CVDCreate(args CreateArgs) (CommandOutput, error) { tempdirEnv := map[string]string{ "HOME": tc.tempdir, } @@ -214,13 +214,14 @@ func (tc *TestContext) CVDCreate(args CreateArgs) error { if len(args.Args) > 0 { createCmd = append(createCmd, args.Args...) } - if _, err := tc.RunCmdWithEnv(createCmd, tempdirEnv); err != nil { + res, err := tc.RunCmdWithEnv(createCmd, tempdirEnv) + if err != nil { log.Printf("Failed to create instance(s): %w", err) - return err + return res, err } tc.Cleanup(func() { tc.CVDStop() }) - return nil + return res, nil } // Performs `cvd stop`. @@ -582,7 +583,7 @@ func RunXts(t *testing.T, cuttlefishArgs FetchAndCreateArgs, xtsArgs XtsArgs) { t.Fatal(err) } - if err := tc.CVDCreate(cuttlefishArgs.Create); err != nil { + if _, err := tc.CVDCreate(cuttlefishArgs.Create); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/cvd_create_tests/main_test.go b/e2etests/cvd/cvd_create_tests/main_test.go index 326c0f9b4b7..08685ff9757 100644 --- a/e2etests/cvd/cvd_create_tests/main_test.go +++ b/e2etests/cvd/cvd_create_tests/main_test.go @@ -60,7 +60,7 @@ func TestCvdCreate(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/cvd_powerwash_tests/main_test.go b/e2etests/cvd/cvd_powerwash_tests/main_test.go index 81a34bb3bbf..634b4e03a8b 100644 --- a/e2etests/cvd/cvd_powerwash_tests/main_test.go +++ b/e2etests/cvd/cvd_powerwash_tests/main_test.go @@ -44,7 +44,7 @@ func TestCvdPowerwash(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/display_tests/main_test.go b/e2etests/cvd/display_tests/main_test.go index 3cf4bbabed5..d86b19a44ed 100644 --- a/e2etests/cvd/display_tests/main_test.go +++ b/e2etests/cvd/display_tests/main_test.go @@ -24,14 +24,14 @@ func addDisplay(c e2etests.TestContext, t *testing.T) { c.SetUp(t) defer c.TearDown() - if _, err := c.CVDFetch(e2etests.FetchArgs{ + if res, err := c.CVDFetch(e2etests.FetchArgs{ DefaultBuildBranch: "aosp-android-latest-release", DefaultBuildTarget: "aosp_cf_x86_64_only_phone-userdebug", }); err != nil { - t.Fatal(err) + t.Fatalf("cvd fetch failed with %v, stderr:%s", err, res.Stderr) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } @@ -51,7 +51,7 @@ func listDisplays(c e2etests.TestContext, t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/env_tests/main_test.go b/e2etests/cvd/env_tests/main_test.go index e1f4a6ab293..0d292466dcb 100644 --- a/e2etests/cvd/env_tests/main_test.go +++ b/e2etests/cvd/env_tests/main_test.go @@ -32,7 +32,7 @@ func TestListEnvServices(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/graphics_detector_tests/main_test.go b/e2etests/cvd/graphics_detector_tests/main_test.go index 76aeb193075..c1eb2f3eb2d 100644 --- a/e2etests/cvd/graphics_detector_tests/main_test.go +++ b/e2etests/cvd/graphics_detector_tests/main_test.go @@ -32,7 +32,7 @@ func TestLaunchingWithAutoEnablesGfxstream(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/media_tests/v4l2compliance/main_test.go b/e2etests/cvd/media_tests/v4l2compliance/main_test.go index f5f1dbc612f..2f92f6b76e9 100644 --- a/e2etests/cvd/media_tests/v4l2compliance/main_test.go +++ b/e2etests/cvd/media_tests/v4l2compliance/main_test.go @@ -51,7 +51,11 @@ func TestEmulatedCameraV4l2Compliance(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{Args: []string{fmt.Sprintf("--media=type=%s", tc.mediaType)}}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{ + Args: []string{ + fmt.Sprintf("--media=type=%s", tc.mediaType), + }, + }); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/metrics_tests/main_test.go b/e2etests/cvd/metrics_tests/main_test.go index a6b25caf0df..e07770e3a0b 100644 --- a/e2etests/cvd/metrics_tests/main_test.go +++ b/e2etests/cvd/metrics_tests/main_test.go @@ -44,7 +44,7 @@ func TestMetrics(t *testing.T) { t.Fatal(err) } - if err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { + if _, err := c.CVDCreate(e2etests.CreateArgs{}); err != nil { t.Fatal(err) } diff --git a/e2etests/cvd/networking_tests/main_test.go b/e2etests/cvd/networking_tests/main_test.go index 719f6595017..cfe1e0df640 100644 --- a/e2etests/cvd/networking_tests/main_test.go +++ b/e2etests/cvd/networking_tests/main_test.go @@ -66,7 +66,7 @@ func TestDeviceNetworking(t *testing.T) { } t.Log("Launching Cuttlefish...") - if err := c.CVDCreate(tc.createArgs); err != nil { + if _, err := c.CVDCreate(tc.createArgs); err != nil { t.Fatal(err) } From 537044ebcea09c5003572b4e01cd4b88dd78db6c Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Wed, 29 Jul 2026 16:25:30 -0400 Subject: [PATCH 24/52] Run CtsCameraTestCases:android.hardware.camera2.cts.CameraManagerTest Bug: b/533512719 --- e2etests/cvd/media_tests/cts/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go index fc1e80d0a8d..59455443d37 100644 --- a/e2etests/cvd/media_tests/cts/main_test.go +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -40,6 +40,7 @@ func TestEmulatedCamera(t *testing.T) { XtsType: "cts", XtsArgs: []string{ "--include-filter=CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures", + "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.CameraManagerTest", }, }) } From 51e4d4bdabce3d8bd829d37c36b16348f7cd9f8d Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Thu, 30 Jul 2026 13:05:49 -0400 Subject: [PATCH 25/52] Use fixed crun version in relevant GitHub Actions GitHub Actions runners have been failing with non-deterministic failures during e2e tests with the error "crun: unknown version specified". This can occur because newer versions of Podman on the `ubuntu-24.04` runner generate OCI configurations that are incompatible with the older version of `crun` pre-installed on the runner. BUG=b/540850996 Assisted-by: Jetski:Gemini 3.5 Flash --- .../run-cw-sharded-e2e-test/action.yaml | 2 ++ .github/actions/upgrade-crun/action.yaml | 29 +++++++++++++++++++ .github/workflows/presubmit.yaml | 6 ++++ 3 files changed, 37 insertions(+) create mode 100644 .github/actions/upgrade-crun/action.yaml diff --git a/.github/actions/run-cw-sharded-e2e-test/action.yaml b/.github/actions/run-cw-sharded-e2e-test/action.yaml index 4687e55504f..5fa87cc828b 100644 --- a/.github/actions/run-cw-sharded-e2e-test/action.yaml +++ b/.github/actions/run-cw-sharded-e2e-test/action.yaml @@ -16,6 +16,8 @@ runs: with: name: android-cuttlefish-e2etest-image-tar github-token: ${{ github.token }} + - name: Upgrade crun + uses: ./.github/actions/upgrade-crun - name: Run tests shell: bash env: diff --git a/.github/actions/upgrade-crun/action.yaml b/.github/actions/upgrade-crun/action.yaml new file mode 100644 index 00000000000..53dc2120d50 --- /dev/null +++ b/.github/actions/upgrade-crun/action.yaml @@ -0,0 +1,29 @@ +name: 'Upgrade crun' +description: 'Upgrade crun to latest version to avoid OCI compatibility issues' +runs: + using: "composite" + steps: + - name: Upgrade crun + shell: bash + run: | + TARGET_VERSION="1.28" + EXPECTED_HASH="2aa6b7024a9c9f153895c0d11ae233d3758f54844011c3a039e3e89048d01d42" + CRUN_PATH=$(which crun || echo "/usr/bin/crun") + echo "Current crun path: $CRUN_PATH" + if [ -f "$CRUN_PATH" ]; then + echo "Current crun version:" + $CRUN_PATH --version + fi + + TEMP_CRUN=$(mktemp) + echo "Downloading crun $TARGET_VERSION..." + curl -L -o "$TEMP_CRUN" https://github.com/containers/crun/releases/download/${TARGET_VERSION}/crun-${TARGET_VERSION}-linux-amd64 + + echo "Verifying hash..." + echo "$EXPECTED_HASH $TEMP_CRUN" | sha256sum --check + + echo "Installing crun..." + sudo mv "$TEMP_CRUN" "$CRUN_PATH" + sudo chmod +x "$CRUN_PATH" + echo "Upgraded crun version:" + $CRUN_PATH --version diff --git a/.github/workflows/presubmit.yaml b/.github/workflows/presubmit.yaml index 86275860d06..ac5948fd54d 100644 --- a/.github/workflows/presubmit.yaml +++ b/.github/workflows/presubmit.yaml @@ -304,6 +304,8 @@ jobs: with: name: debs_amd64 github-token: ${{ github.token }} + - name: Upgrade crun + uses: ./.github/actions/upgrade-crun - name: Build image run: | tar -xvf debs_amd64.tar @@ -363,6 +365,8 @@ jobs: with: name: android-cuttlefish-e2etest-image-tar github-token: ${{ github.token }} + - name: Upgrade crun + uses: ./.github/actions/upgrade-crun - name: Run tests run: | sudo podman info @@ -509,6 +513,8 @@ jobs: uses: actions/download-artifact@v7 with: name: cuttlefish-orchestration-amd64 + - name: Upgrade crun + uses: ./.github/actions/upgrade-crun - name: Load docker image as podman image run: | sudo sysctl -w kernel.unprivileged_userns_clone=1 From 5796b30b2e733703ed589379699389f354ff91ef Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Fri, 31 Jul 2026 12:52:08 -0400 Subject: [PATCH 26/52] Add CtsCameraTestCases:android.hardware.camera2.cts.FastBasicsTest. Bug: b/537744179 --- e2etests/cvd/media_tests/cts/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go index 59455443d37..e1b5c2b34d3 100644 --- a/e2etests/cvd/media_tests/cts/main_test.go +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -41,6 +41,7 @@ func TestEmulatedCamera(t *testing.T) { XtsArgs: []string{ "--include-filter=CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures", "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.CameraManagerTest", + "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.FastBasicsTest", }, }) } From 90566155a5fed6c3ee0f697a968d454ae613a404 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Fri, 31 Jul 2026 10:21:49 -0700 Subject: [PATCH 27/52] Fix build warnings in vhost_user_media ``` warning: unused variable: `idx` --> cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs:997:18 | 997 | for (idx, ctrl) in ctrl_array.iter().enumerate() { | ^^^ help: if this is intentional, prefix it with an underscore: `_idx` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `idx` --> cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs:1006:14 | 1006 | for (idx, ctrl) in ctrl_array.iter_mut().enumerate() { | ^^^ help: if this is intentional, prefix it with an underscore: `_idx` warning: unused variable: `idx` --> cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs:1117:18 | 1117 | for (idx, ctrl) in ctrl_array.iter().enumerate() { | ^^^ help: if this is intentional, prefix it with an underscore: `_idx` warning: unused variable: `idx` --> cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs:1126:14 | 1126 | for (idx, ctrl) in ctrl_array.iter_mut().enumerate() { | ^^^ help: if this is intentional, prefix it with an underscore: `_idx` warning: 4 warnings emitted ``` Bug: b/541272143 --- .../vhost_user_media/emulated_camera_mplane/src/device.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs index 6986837e048..a19c39407e8 100644 --- a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs +++ b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs @@ -994,7 +994,7 @@ where // Ensure all requested controls belong to the selected class. if let CtrlWhich::Class(class_id) = which { - for (idx, ctrl) in ctrl_array.iter().enumerate() { + for (_idx, ctrl) in ctrl_array.iter().enumerate() { if v4l2_ctrl_id2which(ctrl.id) != class_id { ctrls.error_idx = ctrls.count; return Err(libc::EINVAL); @@ -1003,7 +1003,7 @@ where } // Process controls. Class controls are write-only headers and must fail on read. - for (idx, ctrl) in ctrl_array.iter_mut().enumerate() { + for (_idx, ctrl) in ctrl_array.iter_mut().enumerate() { match ctrl.id { bindings::V4L2_CID_USER_CLASS | bindings::V4L2_CID_CAMERA_CLASS => { ctrls.error_idx = ctrls.count; @@ -1114,7 +1114,7 @@ where // Ensure all requested controls belong to the selected class. if let CtrlWhich::Class(class_id) = which { - for (idx, ctrl) in ctrl_array.iter().enumerate() { + for (_idx, ctrl) in ctrl_array.iter().enumerate() { if v4l2_ctrl_id2which(ctrl.id) != class_id { ctrls.error_idx = ctrls.count; return Err(libc::EINVAL); @@ -1123,7 +1123,7 @@ where } // Apply control values. Class controls are read-only headers and must fail on write/try. - for (idx, ctrl) in ctrl_array.iter_mut().enumerate() { + for (_idx, ctrl) in ctrl_array.iter_mut().enumerate() { match ctrl.id { bindings::V4L2_CID_USER_CLASS | bindings::V4L2_CID_CAMERA_CLASS => { ctrls.error_idx = ctrls.count; From 648e7646779a6171e53c766956a249a263334b01 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Fri, 31 Jul 2026 17:01:04 -0400 Subject: [PATCH 28/52] Add CtsCameraTestCases:android.hardware.camera2.cts.CaptureResultTest Bug: b/537422778 --- e2etests/cvd/media_tests/cts/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go index e1b5c2b34d3..3fd76b76fe4 100644 --- a/e2etests/cvd/media_tests/cts/main_test.go +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -41,6 +41,7 @@ func TestEmulatedCamera(t *testing.T) { XtsArgs: []string{ "--include-filter=CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures", "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.CameraManagerTest", + "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.CaptureResultTest", "--include-filter=CtsCameraTestCases android.hardware.camera2.cts.FastBasicsTest", }, }) From 0dc1b57fb41cbc61325299717592d5e987baa7f1 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Fri, 31 Jul 2026 16:26:57 -0400 Subject: [PATCH 29/52] cvd: Update --media flag format to [type]:[key=value] Modify --media flag parsing logic to support the new pattern: "--media=[type]:[key1]=[val1]:[key2]=[val2]" e.g. "--media=v4l2_emulated_camera_mplane:lens_facing=BACK" This clearly separates the primary media type from its optional properties using `:`. Bug: b/541325033 Assisted-by: Jetski:Gemini 3.5 Flash --- .../cvd/cli/parser/flags_parser_test.cc | 8 ++-- .../cli/parser/instance/cf_media_configs.cpp | 8 ++-- .../cvd/cuttlefish/host/libs/config/media.cpp | 37 ++++++++++--------- base/cvd/cuttlefish/host/libs/config/media.h | 15 +++++--- e2etests/cvd/media_tests/cts/main_test.go | 4 +- .../media_tests/v4l2compliance/main_test.go | 2 +- 6 files changed, 39 insertions(+), 35 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/flags_parser_test.cc b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/flags_parser_test.cc index b0ca0d1c7b8..bc41537b144 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/flags_parser_test.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/flags_parser_test.cc @@ -374,7 +374,7 @@ TEST(FlagsParserTest, ParseMediaSplaneSingleInstance) { << "Invalid Json string"; auto serialized_data = LaunchCvdParserTester(json_configs); EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); - EXPECT_TRUE(FindConfig(*serialized_data, "--media=type=v4l2_emulated_camera_splane")) + EXPECT_TRUE(FindConfig(*serialized_data, "--media=v4l2_emulated_camera_splane")) << "media flag is missing or wrongly formatted"; } @@ -407,7 +407,7 @@ TEST(FlagsParserTest, ParseMediaSplaneTwoDevices) { auto serialized_data = LaunchCvdParserTester(json_configs); EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); EXPECT_EQ(std::count(serialized_data->begin(), serialized_data->end(), - "--media=type=v4l2_emulated_camera_splane"), + "--media=v4l2_emulated_camera_splane"), 2); } @@ -437,7 +437,7 @@ TEST(FlagsParserTest, ParseMediaMplane) { auto serialized_data = LaunchCvdParserTester(json_configs); EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); - EXPECT_TRUE(FindConfig(*serialized_data, "--media=type=v4l2_emulated_camera_mplane")) + EXPECT_TRUE(FindConfig(*serialized_data, "--media=v4l2_emulated_camera_mplane")) << "media flag is missing or wrongly formatted"; } @@ -469,7 +469,7 @@ TEST(FlagsParserTest, ParseMediaV4l2Proxy) { auto serialized_data = LaunchCvdParserTester(json_configs); EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace(); - EXPECT_TRUE(FindConfig(*serialized_data, "--media=type=v4l2_proxy")) + EXPECT_TRUE(FindConfig(*serialized_data, "--media=v4l2_proxy")) << "media flag is missing or wrongly formatted"; } diff --git a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_media_configs.cpp b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_media_configs.cpp index 94e6994d597..71b99a0fd20 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_media_configs.cpp +++ b/base/cvd/cuttlefish/host/commands/cvd/cli/parser/instance/cf_media_configs.cpp @@ -41,16 +41,16 @@ Result> GenerateMediaFlags( for (const auto& device : instance.media().devices()) { std::string flag = "--media="; if (device.has_v4l2_emulated_camera_splane()) { - flag += "type=v4l2_emulated_camera_splane"; + flag += "v4l2_emulated_camera_splane"; } else if (device.has_v4l2_emulated_camera_mplane()) { - flag += "type=v4l2_emulated_camera_mplane"; + flag += "v4l2_emulated_camera_mplane"; } else if (device.has_v4l2_proxy()) { // TODO(b/520114678): Use device.v4l2_proxy.device_path when // supported. - flag += "type=v4l2_proxy"; + flag += "v4l2_proxy"; } if (device.has_lens_facing()) { - flag += ",lens_facing=" + device.lens_facing(); + flag += ":lens_facing=" + device.lens_facing(); } flags.push_back(flag); } diff --git a/base/cvd/cuttlefish/host/libs/config/media.cpp b/base/cvd/cuttlefish/host/libs/config/media.cpp index 7adbadaf61c..5ac4103b2e8 100644 --- a/base/cvd/cuttlefish/host/libs/config/media.cpp +++ b/base/cvd/cuttlefish/host/libs/config/media.cpp @@ -16,6 +16,7 @@ #include "cuttlefish/host/libs/config/media.h" +#include #include #include #include @@ -38,30 +39,30 @@ static constexpr char kMediaTypeV4l2Proxy[] = "v4l2_proxy"; Result> ParseMediaConfig( const std::string& flag) { - std::unordered_map props; - if (!flag.empty()) { - const std::vector pairs = absl::StrSplit(flag, ","); - for (const std::string& pair : pairs) { - const std::vector keyvalue = absl::StrSplit(pair, "="); - CF_EXPECT_EQ(keyvalue.size(), 2, - "Invalid media flag key-value: \"" << flag << "\""); - const std::string& prop_key = keyvalue[0]; - const std::string& prop_val = keyvalue[1]; - props[prop_key] = prop_val; - } - } + const std::vector parts = absl::StrSplit(flag, ":"); + CF_EXPECT(!parts.empty(), "Invalid media flag: \"" << flag << "\""); - auto type_it = props.find("type"); - CF_EXPECT(type_it != props.end(), "Missing media type"); + const std::string& type_str = parts[0]; CuttlefishConfig::MediaType type{CuttlefishConfig::MediaType::kUnknown}; - if (type_it->second == kMediaTypeV4l2EmulatedCameraSPlane) { + if (type_str == kMediaTypeV4l2EmulatedCameraSPlane) { type = CuttlefishConfig::MediaType::kV4l2EmulatedCameraSPlane; - } else if (type_it->second == kMediaTypeV4l2EmulatedCameraMPlane) { + } else if (type_str == kMediaTypeV4l2EmulatedCameraMPlane) { type = CuttlefishConfig::MediaType::kV4l2EmulatedCameraMPlane; - } else if (type_it->second == kMediaTypeV4l2Proxy) { + } else if (type_str == kMediaTypeV4l2Proxy) { type = CuttlefishConfig::MediaType::kV4l2Proxy; } else { - return CF_ERRF("Unknown media type value: \"{}\"", type_it->second); + return CF_ERRF("Unknown media type value: \"{}\"", type_str); + } + + std::unordered_map props; + for (size_t i = 1; i < parts.size(); ++i) { + const std::vector keyvalue = absl::StrSplit(parts[i], "="); + CF_EXPECT_EQ(keyvalue.size(), 2, + "Invalid media flag key-value: \"" << parts[i] << "\" in \"" + << flag << "\""); + const std::string& prop_key = keyvalue[0]; + const std::string& prop_val = keyvalue[1]; + props[prop_key] = prop_val; } std::string lens_facing = ""; diff --git a/base/cvd/cuttlefish/host/libs/config/media.h b/base/cvd/cuttlefish/host/libs/config/media.h index 946cebf64fc..fd329ce2021 100644 --- a/base/cvd/cuttlefish/host/libs/config/media.h +++ b/base/cvd/cuttlefish/host/libs/config/media.h @@ -24,15 +24,18 @@ namespace cuttlefish { constexpr const char kMediaFlag[] = "media"; constexpr const char kMediaHelp[] = - "Comma separated key=value pairs of media device properties. Supported " - "properties:\n" - " 'type': optional, defaults to 'v4l2_emulated_camera_splane', supported values:\n" - " 'v4l2_emulated_camera_splane': emulated media capture device (single-plane)\n" - " 'v4l2_emulated_camera_mplane': emulated media capture device (multi-plane)\n" + "Colon separated media device properties: " + "\"[type]:[key1]=[val1]:[key2]=[val2]\". " + "Supported types:\n" + " 'v4l2_emulated_camera_splane': emulated media capture device " + "(single-plane)\n" + " 'v4l2_emulated_camera_mplane': emulated media capture device " + "(multi-plane)\n" " 'v4l2_proxy': proxy a host V4L2 device into the guest\n" + "Supported keys:\n" " 'lens_facing': optional, supported values: 'FRONT', 'BACK', 'EXTERNAL'\n" "Example usage:\n" - " --media=type=v4l2_emulated_camera_splane,lens_facing=BACK\n"; + " --media=v4l2_emulated_camera_mplane:lens_facing=BACK\n"; Result> ParseMediaConfig( const std::string& flag); diff --git a/e2etests/cvd/media_tests/cts/main_test.go b/e2etests/cvd/media_tests/cts/main_test.go index 3fd76b76fe4..bffd2bf451c 100644 --- a/e2etests/cvd/media_tests/cts/main_test.go +++ b/e2etests/cvd/media_tests/cts/main_test.go @@ -31,8 +31,8 @@ func TestEmulatedCamera(t *testing.T) { }, Create: e2etests.CreateArgs{ Args: []string{ - "--media=type=v4l2_emulated_camera_mplane,lens_facing=BACK", - "--media=type=v4l2_emulated_camera_mplane,lens_facing=FRONT", + "--media=v4l2_emulated_camera_mplane:lens_facing=BACK", + "--media=v4l2_emulated_camera_mplane:lens_facing=FRONT", }, }, }, diff --git a/e2etests/cvd/media_tests/v4l2compliance/main_test.go b/e2etests/cvd/media_tests/v4l2compliance/main_test.go index 2f92f6b76e9..3af9d484d08 100644 --- a/e2etests/cvd/media_tests/v4l2compliance/main_test.go +++ b/e2etests/cvd/media_tests/v4l2compliance/main_test.go @@ -53,7 +53,7 @@ func TestEmulatedCameraV4l2Compliance(t *testing.T) { if _, err := c.CVDCreate(e2etests.CreateArgs{ Args: []string{ - fmt.Sprintf("--media=type=%s", tc.mediaType), + fmt.Sprintf("--media=%s", tc.mediaType), }, }); err != nil { t.Fatal(err) From bcddcade2313ac4d8fe2e41084d05c2e3c8b94c1 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Wed, 29 Jul 2026 16:17:52 -0400 Subject: [PATCH 30/52] [emulated_camera_mplane] Support dynamic resolution selection. Enable dynamic resolution selection for the emulated camera device by implementing the V4L2 S_FMT and TRY_FMT allowing the guest HAL (or host-side tools) to query supported sizes and change the camera resolution dynamically. This capability is relevant for passing CtsCameraTestCases:android.hardware.camera2.cts.RecordingTest#testBasicRecording. Relevant v4l2-ctl commands to verify this behavior: 1. List supported resolutions and formats: $ adb shell "su 0 v4l2-ctl -d /dev/video1 --list-formats-ext" 2. Query current resolution and format: $ adb shell "su 0 v4l2-ctl -d /dev/video1 -V" 3. Set a new resolution (e.g., 1280x720): $ adb shell "su 0 v4l2-ctl -d /dev/video1 -v width=1280,height=720,pixelformat=YM12" Bug: b/537805477 Assisted-by: Jetski:Gemini 3.5 Flash --- .../emulated_camera_mplane/src/device.rs | 139 +++++++++++++----- 1 file changed, 100 insertions(+), 39 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs index a19c39407e8..9e3a2e61fe2 100644 --- a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs +++ b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs @@ -171,7 +171,7 @@ impl Buffer { } /// Update the state of the buffer as well as its V4L2 representation. - fn set_state(&mut self, state: BufferState) { + fn set_state(&mut self, state: BufferState, width: u32, height: u32) { let mut flags = self.v4l2_buffer.flags(); match state { BufferState::New => { @@ -196,9 +196,9 @@ impl Buffer { { let planes = self.v4l2_buffer.planes_with_backing_iter_mut(); if let V4l2PlanesWithBackingMut::Mmap(mut planes) = planes { - *planes.next().unwrap().bytesused = WIDTH * HEIGHT; - *planes.next().unwrap().bytesused = WIDTH * HEIGHT / 4; - *planes.next().unwrap().bytesused = WIDTH * HEIGHT / 4; + *planes.next().unwrap().bytesused = width * height; + *planes.next().unwrap().bytesused = width * height / 4; + *planes.next().unwrap().bytesused = width * height / 4; } } self.v4l2_buffer.set_sequence(sequence); @@ -246,6 +246,8 @@ impl EmulatedCameraSession { fn write_pattern( iteration: u64, controls: &CameraControls, + width: u32, + height: u32, mut sink_y: WY, mut sink_u: WU, mut sink_v: WV, @@ -261,13 +263,13 @@ impl EmulatedCameraSession { let y = ((base_y as f32) * (controls.gain.value() as f32 / Gain::MIN as f32)).min(255.0) as u8; let u = ((iteration + 64) % 256) as u8; let v = ((iteration + 128) % 256) as u8; - for _ in 0..(WIDTH * HEIGHT) { + for _ in 0..(width * height) { writer_y.write_all(&[y]).map_err(|_| libc::EIO)?; } - for _ in 0..(WIDTH * HEIGHT / 4) { + for _ in 0..(width * height / 4) { writer_u.write_all(&[u]).map_err(|_| libc::EIO)?; } - for _ in 0..(WIDTH * HEIGHT / 4) { + for _ in 0..(width * height / 4) { writer_v.write_all(&[v]).map_err(|_| libc::EIO)?; } Ok(()) @@ -278,6 +280,8 @@ impl EmulatedCameraSession { &mut self, evt_queue: &mut Q, controls: &CameraControls, + width: u32, + height: u32, ) -> IoctlResult<()> { while let Some(buf_id) = self.queued_buffers.pop_front() { let iteration = self.iteration; @@ -294,6 +298,8 @@ impl EmulatedCameraSession { Self::write_pattern( iteration, controls, + width, + height, buffer.planes[0].fd.as_file(), buffer.planes[1].fd.as_file(), buffer.planes[2].fd.as_file(), @@ -301,7 +307,7 @@ impl EmulatedCameraSession { buffer.set_state(BufferState::Outgoing { sequence: iteration as u32, - }); + }, width, height); evt_queue.send_event(V4l2Event::DequeueBuffer(DequeueBufferEvent::new( self.id, buffer.v4l2_buffer.clone(), @@ -332,6 +338,10 @@ pub struct EmulatedCamera, /// Camera controls. controls: CameraControls, + /// Width of the video. + width: u32, + /// Height of the video. + height: u32, } impl EmulatedCamera @@ -345,6 +355,8 @@ where mmap_manager: MmapMappingManager::from(mapper), active_session: None, controls: CameraControls::new(lens_facing), + width: 640, + height: 480, } } @@ -502,6 +514,11 @@ const WIDTH: u32 = 640; const HEIGHT: u32 = 480; const FRAME_RATE: u32 = 30; +const SUPPORTED_SIZES: [(u32, u32); 2] = [ + (640, 480), + (1280, 720), +]; + const INPUTS: [bindings::v4l2_input; 1] = [bindings::v4l2_input { index: 0, name: *b"Default\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", @@ -518,28 +535,34 @@ fn default_fmtdesc(queue: QueueType) -> v4l2_fmtdesc { } } -fn default_fmt(queue: QueueType) -> v4l2_format { +fn session_fmt(queue: QueueType, width: u32, height: u32) -> v4l2_format { let pix_mp = bindings::v4l2_pix_format_mplane { - width: WIDTH, - height: HEIGHT, + width, + height, pixelformat: PIXELFORMAT, field: bindings::v4l2_field_V4L2_FIELD_NONE, colorspace: bindings::v4l2_colorspace_V4L2_COLORSPACE_SRGB, num_planes: 3, plane_fmt: [ bindings::v4l2_plane_pix_format { - sizeimage: WIDTH * HEIGHT, - bytesperline: WIDTH, + // Size of Y plane + sizeimage: width * height, + // Bytes per line for Y plane + bytesperline: width, ..Default::default() }, bindings::v4l2_plane_pix_format { - sizeimage: WIDTH * HEIGHT / 4, - bytesperline: WIDTH / 2, + // Size of U plane (chroma subsampled by 2 in both directions) + sizeimage: width * height / 4, + // Bytes per line for U plane + bytesperline: width / 2, ..Default::default() }, bindings::v4l2_plane_pix_format { - sizeimage: WIDTH * HEIGHT / 4, - bytesperline: WIDTH / 2, + // Size of V plane + sizeimage: width * height / 4, + // Bytes per line for V plane + bytesperline: width / 2, ..Default::default() }, Default::default(), @@ -557,6 +580,10 @@ fn default_fmt(queue: QueueType) -> v4l2_format { } } +fn default_fmt(queue: QueueType) -> v4l2_format { + session_fmt(queue, WIDTH, HEIGHT) +} + /// Implementations of the ioctls required by a v4l2 CAPTURE device. impl VirtioMediaIoctlHandler for EmulatedCamera where @@ -581,35 +608,60 @@ where Ok(default_fmtdesc(queue)) } - fn g_fmt(&mut self, _session: &Self::Session, queue: QueueType) -> IoctlResult { + fn g_fmt(&mut self, session: &Self::Session, queue: QueueType) -> IoctlResult { if queue != QueueType::VideoCaptureMplane { return Err(libc::EINVAL); } - Ok(default_fmt(queue)) + log::info!("g_fmt: returning {}x{}", self.width, self.height); + Ok(session_fmt(queue, self.width, self.height)) } fn s_fmt( &mut self, - _session: &mut Self::Session, + session: &mut Self::Session, queue: QueueType, - _format: v4l2_format, + format: v4l2_format, ) -> IoctlResult { if queue != QueueType::VideoCaptureMplane { return Err(libc::EINVAL); } - Ok(default_fmt(queue)) + + let pix_mp = unsafe { format.fmt.pix_mp }; + let req_width = pix_mp.width; + let req_height = pix_mp.height; + log::info!("s_fmt: requested {}x{}", req_width, req_height); + + if SUPPORTED_SIZES.contains(&(req_width, req_height)) { + self.width = req_width; + self.height = req_height; + log::info!("s_fmt: set resolution to {}x{}", req_width, req_height); + } else { + log::info!("s_fmt: requested resolution {}x{} not supported, keeping {}x{}", req_width, req_height, self.width, self.height); + } + + Ok(session_fmt(queue, self.width, self.height)) } fn try_fmt( &mut self, - _session: &Self::Session, + session: &Self::Session, queue: QueueType, - _format: v4l2_format, + format: v4l2_format, ) -> IoctlResult { if queue != QueueType::VideoCaptureMplane { return Err(libc::EINVAL); } - Ok(default_fmt(queue)) + + let pix_mp = unsafe { format.fmt.pix_mp }; + let req_width = pix_mp.width; + let req_height = pix_mp.height; + log::info!("try_fmt: requested {}x{}", req_width, req_height); + + if SUPPORTED_SIZES.contains(&(req_width, req_height)) { + Ok(session_fmt(queue, req_width, req_height)) + } else { + Ok(session_fmt(queue, self.width, self.height)) + } } fn g_parm( @@ -689,7 +741,7 @@ where // TODO factorize with streamoff. session.queued_buffers.clear(); for buffer in session.buffers.iter_mut() { - buffer.set_state(BufferState::New); + buffer.set_state(BufferState::New, self.width, self.height); } self.active_session = Some(session.id); } @@ -702,9 +754,9 @@ where } } - let size_y = (WIDTH * HEIGHT) as u64; - let size_u = (WIDTH * HEIGHT / 4) as u64; - let size_v = (WIDTH * HEIGHT / 4) as u64; + let size_y = (self.width * self.height) as u64; + let size_u = (self.width * self.height / 4) as u64; + let size_v = (self.width * self.height / 4) as u64; session.buffers = (0..count) .map(|i| -> std::result::Result { @@ -824,13 +876,13 @@ where return Err(libc::EINVAL); } - host_buffer.set_state(BufferState::Incoming); + host_buffer.set_state(BufferState::Incoming, self.width, self.height); session.queued_buffers.push_back(buffer.index() as usize); let buffer = host_buffer.v4l2_buffer.clone(); if session.streaming { - session.process_queued_buffers(&mut self.evt_queue, &self.controls)?; + session.process_queued_buffers(&mut self.evt_queue, &self.controls, self.width, self.height)?; } Ok(buffer) @@ -842,7 +894,7 @@ where } session.streaming = true; - session.process_queued_buffers(&mut self.evt_queue, &self.controls)?; + session.process_queued_buffers(&mut self.evt_queue, &self.controls, self.width, self.height)?; Ok(()) } @@ -854,7 +906,7 @@ where session.streaming = false; session.queued_buffers.clear(); for buffer in session.buffers.iter_mut() { - buffer.set_state(BufferState::New); + buffer.set_state(BufferState::New, self.width, self.height); } Ok(()) @@ -882,21 +934,26 @@ where index: u32, pixel_format: u32, ) -> IoctlResult { + log::info!("enum_framesizes: index {}, format {}", index, pixel_format); if pixel_format != PIXELFORMAT { + log::info!("enum_framesizes: format {} not supported", pixel_format); return Err(libc::EINVAL); } - if index > 0 { - return Err(libc::EINVAL); - } + + let &(width, height) = SUPPORTED_SIZES.get(index as usize).ok_or_else(|| { + log::info!("enum_framesizes: index {} out of bounds", index); + libc::EINVAL + })?; + log::info!("enum_framesizes: returning {}x{}", width, height); Ok(bindings::v4l2_frmsizeenum { index, pixel_format, type_: bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE, __bindgen_anon_1: bindings::v4l2_frmsizeenum__bindgen_ty_1 { discrete: bindings::v4l2_frmsize_discrete { - width: WIDTH, - height: HEIGHT, + width, + height, }, }, ..Default::default() @@ -911,13 +968,17 @@ where width: u32, height: u32, ) -> IoctlResult { + log::info!("enum_frameintervals: index {}, format {}, {}x{}", index, pixel_format, width, height); if pixel_format != PIXELFORMAT { + log::info!("enum_frameintervals: format {} not supported", pixel_format); return Err(libc::EINVAL); } - if width != WIDTH || height != HEIGHT { + if !SUPPORTED_SIZES.contains(&(width, height)) { + log::info!("enum_frameintervals: size {}x{} not supported", width, height); return Err(libc::EINVAL); } if index > 0 { + log::info!("enum_frameintervals: index {} > 0 not supported", index); return Err(libc::EINVAL); } From 26cd13639744edf1db54f3c8ab30e304887d7ca2 Mon Sep 17 00:00:00 2001 From: Sarah Kim Date: Wed, 29 Jul 2026 09:02:23 -0700 Subject: [PATCH 31/52] #VibeCoding cuttlefish: Add iccprofile_for_sim1.xml and CTS profile for dual-SIM support Add simulator profile for SIM 1 and CTS carrier API test profile to enable dual-SIM modem simulation support. These profiles are identical to their SIM 0 counterparts except for the ICCID (and its binary EF representation), IMSI, and EID. Also ignore SIGPIPE from clients in modem simulator. BUG=532745689 Test: http://go/forrest-run/L25500030157036716 --- .../etc/files/iccprofile_for_sim1.xml | 185 +++++++++++++++ ...le_for_sim1_for_CtsCarrierApiTestCases.xml | 211 ++++++++++++++++++ .../host/commands/modem_simulator/main.cpp | 4 +- base/cvd/cuttlefish/package/BUILD.bazel | 2 + e2etests/debian_substitution_marker | 10 + 5 files changed, 411 insertions(+), 1 deletion(-) create mode 100755 base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1.xml create mode 100755 base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1.xml b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1.xml new file mode 100755 index 00000000000..f1f77b54035 --- /dev/null +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1.xml @@ -0,0 +1,185 @@ + + + + 144,0,621A8205422100300483022F008A01058B032F0601800200C08801F0 + 144,0,61184F10A0000003431002FF86FF0389FFFFFFFF50044353494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,61184F10A0000000871002FF86FF0389FFFFFFFF50045553494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,62178202412183022FE28A01058B032F06038002000A880110 + 144,0,98683081462002318389 + + 89860318640220133898 + + + 144,0,62178202412183022F058A01058B032F060280020004880128 + 144,0,FFFFFFFF + + + + + + 144,0,62198205422100400283024F308A01058B036F0606800200808800 + 144,0,A81EC0034F3A01C1034F3306C5034F0902C4034F1104C6034F2503C9034F3107A905CA034F5008AA0FC2034F4A09C7034F4B0AC8034F4C0BFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A8205422100140A83024F4C8A01058B036F060E800200C8880158 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A82054221001C1483024F3A8A01058B036F060E80020230880108 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A820542210001FA83024F338A01058B036F060E800200FA880130 + + + 144,0,621A820542210002FA83024F098A01058B036F060E800201F4880110 + + + 144,0,621A82054221000FFA83024F118A01058B036F060E80020EA6880120 + + + + + + + + 311740123456790 + + + 144,0,621982054221001C0283026F408A01058B036F0605800200388800 + 144,0,000000000000000000000000000007915155214365F7FFFFFFFFFFFF + + + 144,0,62198205422100050183026FC98A01058B036F0602800200058800 + 144,0,0100000000 + + + 144,0,621982054221001C0283026F408A01058B036F06058002003E8800 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07915155674523F1FFFFFFFFFFFF + + + 144,0,62178202412183026FAD8A01058B036F060180020004880118 + 144,0,00000003 + + + 144,0,62198205422100050183026FCA8A01058B036F060E800200058800 + 144,0,0000000000 + + + 106,130 + + + 144,0,621C8202412183026F7BA5038001718A01058B036F06038002001E880168 + 144,0,64F00064F02064F04064F07064F080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621982054221001C0A83026F3B8A01058B036F0605800201188800 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + + + + + 4,6124 + 76,62228202412183025031A503C001408A01058B066F0601010001800200108102002288009000 + 36,A706300404024401A5063004040244029000 + + + + 6,019000 + 4,6b00 + + + + + + + + PINSTATE_UNKNOWN + 1234 + 12345678 + 3 + 10 + 1234 + 12345678 + 3 + 10 + + + + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + + + + + + + + + + + + + + + + + + + + + 3F979580BFFE8210428031A073BE211797 + 89049032000001000000000254806853 + + diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml new file mode 100755 index 00000000000..c3e6db772bc --- /dev/null +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/etc/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml @@ -0,0 +1,211 @@ + + + + 144,0,621A8205422100300483022F008A01058B032F0601800200C08801F0 + 144,0,61184F10A0000003431002FF86FF0389FFFFFFFF50044353494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,61184F10A0000000871002FF86FF0389FFFFFFFF50045553494DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,62178202412183022FE28A01058B032F06038002000A880110 + 144,0,98683081462002318389 + + 89860318640220133898 + + + 144,0,62178202412183022F058A01058B032F060280020004880128 + 144,0,FFFFFFFF + + + + + + 144,0,62198205422100400283024F308A01058B036F0606800200808800 + 144,0,A81EC0034F3A01C1034F3306C5034F0902C4034F1104C6034F2503C9034F3107A905CA034F5008AA0FC2034F4A09C7034F4B0AC8034F4C0BFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A8205422100140A83024F4C8A01058B036F060E800200C8880158 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A82054221001C1483024F3A8A01058B036F060E80020230880108 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621A820542210001FA83024F338A01058B036F060E800200FA880130 + + + 144,0,621A820542210002FA83024F098A01058B036F060E800201F4880110 + + + 144,0,621A82054221000FFA83024F118A01058B036F060E80020EA6880120 + + + + + + + + 311740123456790 + + + 144,0,621982054221001C0283026F408A01058B036F0605800200388800 + 144,0,00000000000000000000000000000891688118109844F0FFFFFFFFFF + + + 144,0,62258205422100040183026FC9A503C001408A01058B066F060103000080020004810200188800 + 144,0,01000000 + + + 144,0,62178202412183026FAD8A01058B036F060180020004880118 + 144,0,00000002 + + + 144,0,62258205422100260483026FC7A503C001408A01058B066F060103000080020098810200AC8800 + 144,0 + 144,0 + 144,0 + + + 144,0,62198205422100050183026FCA8A01058B036F060E800200058800 + 144,0,0000000000 + + + 106,130 + + + 144,0,621C8202412183026F7BA5038001718A01058B036F06038002001E880168 + 144,0,64F00064F02064F04064F07064F080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + 144,0,621982054221001C0A83026F3B8A01058B036F0605800201188800 + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + 144,0,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + + + + + + + + 76,62228202412183024300A503C001408A01058B066F0601010001800201DC810201EE88009000 + 516,30088200300404024310301AA0120410A000000476416E64726F696443545340300404024311301AA0120410A000000476416E64726F696443545341300404024312301AA0120410A000000476416E64726F696443545342300404024313301AA0120410A000000476416E64726F696443545343300404024314301AA0120410A000000476416E64726F696443545344300404024315301AA0120410A000000476416E64726F696443545345300404024316301AA0120410A000000476416E64726F6964435453463004040243173010A0080406FFFFFFFFFFFF300404024318301AA0120410A000000476416E64726F696443545347300404024313301AA0129000 + + + 76,62228202412183024318A503C001408A01058B066F0601010001800200188102002A88009000 + 124,3016041461ED377E85D386A8DFEE6B864BD85B0BFAA5AF8130220420CE7B2B47AE2B7552C8F92CC29124279883041FB623A5F194A82C9BF15D492AA09000 + + + + + 6,019000 + 110,62338202782183023F00A50C80016187010183040007DBF08A01058B062F0601020002C60C90016083010183010A83010D8102FFFF9000 + 6,019000 + 4,9000 + 4,6C35 + 4,6B00 + 4,9000 + 4,6D00 + 4,6B00 + 4,6A82 + 4,6A81 + 4,6E00 + 4,9000 + 24,983311111111111111029000 + 78,622382054221004A1283022F06A503C001408A01058B062F060101000080020534810205489000 + + + + + 6,019000 + 4,6b00 + + + + + + + + PINSTATE_UNKNOWN + 1234 + 12345678 + 3 + 10 + 1234 + 12345678 + 3 + 10 + + + + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + DISABLE + + + + + + + + + + + + + + + + + + + + + 3F979580BFFE8210428031A073BE211797 + 89049032000001000000000254806853 + + diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/main.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/main.cpp index 3bfc1ec2e99..040b5cce472 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/main.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/main.cpp @@ -89,7 +89,9 @@ int ModemSimulatorMain(int argc, char** argv) { NvramConfig::InitNvramConfigService(server_fds.size(), FLAGS_sim_type); // Don't get a SIGPIPE from the clients - if (sigaction(SIGPIPE, nullptr, nullptr) != 0) { + struct sigaction sa{}; + sa.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sa, nullptr) != 0) { LOG(ERROR) << "Failed to set SIGPIPE to be ignored: " << strerror(errno); } diff --git a/base/cvd/cuttlefish/package/BUILD.bazel b/base/cvd/cuttlefish/package/BUILD.bazel index 27de4a1cff1..384d90d0042 100644 --- a/base/cvd/cuttlefish/package/BUILD.bazel +++ b/base/cvd/cuttlefish/package/BUILD.bazel @@ -117,6 +117,8 @@ package_files( "cuttlefish-common/etc/cvd_custom_action_config/cuttlefish_example_action_config.json": "//cuttlefish/host/example_custom_actions:custom_action_config.json", "cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml": "//cuttlefish/host/commands/modem_simulator:etc/files/iccprofile_for_sim0_for_CtsCarrierApiTestCases.xml", "cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim0.xml": "//cuttlefish/host/commands/modem_simulator:etc/files/iccprofile_for_sim0.xml", + "cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml": "//cuttlefish/host/commands/modem_simulator:etc/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml", + "cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim1.xml": "//cuttlefish/host/commands/modem_simulator:etc/files/iccprofile_for_sim1.xml", "cuttlefish-common/etc/modem_simulator/files/numeric_operator.xml": "//cuttlefish/host/commands/modem_simulator:etc/files/numeric_operator.xml", # "cuttlefish-common/bin/crosvm": "@crosvm_bin//:crosvm__crosvm", # TODO: b/402274999 - currently requires --enable_sandbox=false "cuttlefish-common/usr/share/webrtc/assets/client.html": "//cuttlefish/host/frontend/webrtc/html_client:client.html", diff --git a/e2etests/debian_substitution_marker b/e2etests/debian_substitution_marker index 2d08e12467a..0557c7d65b0 100644 --- a/e2etests/debian_substitution_marker +++ b/e2etests/debian_substitution_marker @@ -280,6 +280,16 @@ symlinks: { link_name: "etc/modem_simulator/files/iccprofile_for_sim0.xml" } +symlinks: { + target: "/usr/lib/cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml" + link_name: "etc/modem_simulator/files/iccprofile_for_sim1_for_CtsCarrierApiTestCases.xml" +} + +symlinks: { + target: "/usr/lib/cuttlefish-common/etc/modem_simulator/files/iccprofile_for_sim1.xml" + link_name: "etc/modem_simulator/files/iccprofile_for_sim1.xml" +} + symlinks: { target: "/usr/lib/cuttlefish-common/etc/modem_simulator/files/numeric_operator.xml" link_name: "etc/modem_simulator/files/numeric_operator.xml" From 04c237359b5981361c5c16fe5ab2e9401ee3973b Mon Sep 17 00:00:00 2001 From: Bailey Kuo Date: Tue, 4 Aug 2026 04:44:21 +0000 Subject: [PATCH 32/52] cuttlefish: Wire up Netsim UDS socket (--grpc_uds_path) Exposes `EnableNetsimNfc()` instead of netsim_radio_enabled to simplify netsim nfc checking, avoiding passing --grpc_uds_path unconditionally. Bug: 525044943 Test: bazel build //base/cvd/cuttlefish/... TAG=agy CONV=97998051-73aa-44c8-83ac-51de8d5fd83d --- .../host/commands/run_cvd/launch/BUILD.bazel | 1 + .../commands/run_cvd/launch/netsim_server.cpp | 17 +++++++++++++---- .../commands/run_cvd/launch/netsim_server.h | 4 +++- .../host/libs/config/cuttlefish_config.cpp | 4 ++++ .../host/libs/config/cuttlefish_config.h | 2 ++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/launch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/run_cvd/launch/BUILD.bazel index 574f7774578..c3723e31580 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/launch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/run_cvd/launch/BUILD.bazel @@ -281,6 +281,7 @@ cf_cc_library( "//cuttlefish/common/libs/fs", "//cuttlefish/common/libs/utils:files", "//cuttlefish/common/libs/utils:subprocess", + "//cuttlefish/host/commands/run_cvd/launch:grpc_socket_creator", "//cuttlefish/host/libs/config:config_utils", "//cuttlefish/host/libs/config:cuttlefish_config", "//cuttlefish/host/libs/config:known_paths", diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp index 9893456d50f..f795baa25f0 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp +++ b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp @@ -32,6 +32,7 @@ #include "cuttlefish/common/libs/fs/shared_fd.h" #include "cuttlefish/common/libs/utils/files.h" #include "cuttlefish/common/libs/utils/subprocess.h" +#include "cuttlefish/host/commands/run_cvd/launch/grpc_socket_creator.h" #include "cuttlefish/host/libs/config/config_utils.h" #include "cuttlefish/host/libs/config/cuttlefish_config.h" #include "cuttlefish/host/libs/config/known_paths.h" @@ -110,8 +111,9 @@ class Device { class NetsimServer : public CommandSource { public: INJECT(NetsimServer(const CuttlefishConfig& config, - const CuttlefishConfig::InstanceSpecific& instance)) - : config_(config), instance_(instance) {} + const CuttlefishConfig::InstanceSpecific& instance, + GrpcSocketCreator& grpc_socket)) + : config_(config), instance_(instance), grpc_socket_(grpc_socket) {} // CommandSource Result> Commands() override { @@ -123,6 +125,11 @@ class NetsimServer : public CommandSource { // Port configuration. netsimd.AddParameter("--hci_port=", config_.rootcanal_hci_port()); + if (EnableNetsimNfc(config_)) { + netsimd.AddParameter("--grpc_uds_path=", grpc_socket_.CreateGrpcSocket( + "NetsimControlServer")); + } + // When no connector is requested, add the instance number if (config_.netsim_connector_instance_num() == config_.netsim_instance_num()) { @@ -223,7 +230,7 @@ class NetsimServer : public CommandSource { device.chips.emplace_back(chip); } // Add nfc chip if enabled - if (config_.enable_host_nfc() && !config_.enable_host_nfc_connector()) { + if (EnableNetsimNfc(config_)) { Chip chip("NFC"); chip.fd_in = CF_EXPECT(MakeFifo(instance, "nfc_fifo_vm.in")); chip.fd_out = CF_EXPECT(MakeFifo(instance, "nfc_fifo_vm.out")); @@ -277,12 +284,14 @@ class NetsimServer : public CommandSource { std::vector devices_; const CuttlefishConfig& config_; const CuttlefishConfig::InstanceSpecific instance_; + GrpcSocketCreator& grpc_socket_; }; } // namespace fruit::Component> + const CuttlefishConfig::InstanceSpecific, + GrpcSocketCreator>> NetsimServerComponent() { return fruit::createComponent() .addMultibinding() diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.h b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.h index 65c0640ffcd..9dcf3e4a54b 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.h +++ b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.h @@ -17,12 +17,14 @@ #include "fruit/fruit.h" +#include "cuttlefish/host/commands/run_cvd/launch/grpc_socket_creator.h" #include "cuttlefish/host/libs/config/cuttlefish_config.h" namespace cuttlefish { fruit::Component> + const CuttlefishConfig::InstanceSpecific, + GrpcSocketCreator>> NetsimServerComponent(); } // namespace cuttlefish diff --git a/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.cpp b/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.cpp index b4b02251775..cb868aff4e4 100644 --- a/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.cpp +++ b/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.cpp @@ -692,6 +692,10 @@ std::vector CuttlefishConfig::environment_dirs() const { return result; } +bool EnableNetsimNfc(const CuttlefishConfig& config) { + return config.enable_host_nfc() && !config.enable_host_nfc_connector(); +} + bool VmManagerIsCrosvm(const CuttlefishConfig& config) { return VmManagerIsCrosvm(config.vm_manager()); } diff --git a/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.h b/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.h index 218d1df0d44..fd5f4f91c99 100644 --- a/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.h +++ b/base/cvd/cuttlefish/host/libs/config/cuttlefish_config.h @@ -942,4 +942,6 @@ bool VmManagerIsCrosvm(const CuttlefishConfig&); bool VmManagerIsQemu(const CuttlefishConfig&); bool VmManagerIsGem5(const CuttlefishConfig&); +bool EnableNetsimNfc(const CuttlefishConfig& config); + } // namespace cuttlefish From c8b180e7d93b565a5547e8bba2e9bc7ec696d826 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Tue, 4 Aug 2026 14:13:28 -0700 Subject: [PATCH 33/52] feat(cvd): Inject NETSIM_GRPC_PORT as environment variable into netsimd TAG=agy CONV=7e6b7c86-e570-4900-a8f4-683776c7dc60 Assisted-by: Jetski:GeminiNext --- .../host/commands/run_cvd/launch/netsim_server.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp index f795baa25f0..43af27e9587 100644 --- a/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp +++ b/base/cvd/cuttlefish/host/commands/run_cvd/launch/netsim_server.cpp @@ -145,8 +145,16 @@ class NetsimServer : public CommandSource { } // Add parameters from passthrough option --netsim-args. - for (auto const& arg : config_.netsim_args()) { - netsimd.AddParameter(arg); + // NETSIM_GRPC_PORT is extracted and injected as an environment variable; + // all other options are passed as command-line arguments. + for (const std::string& arg : config_.netsim_args()) { + if (arg.starts_with("NETSIM_GRPC_PORT=")) { + const std::string::size_type equals_pos = arg.find('='); + netsimd.AddEnvironmentVariable(arg.substr(0, equals_pos), + arg.substr(equals_pos + 1)); + } else { + netsimd.AddParameter(arg); + } } // Add command for forwarding the HCI port to a vsock server. From 5d02a904a164991d717d8c16e672567e4c9d9be5 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Wed, 5 Aug 2026 15:03:21 -0700 Subject: [PATCH 34/52] Update e2etests to account for new screen size Bug: b/542721218 --- .../create_from_images_zip_test/main_test.go | 2 +- .../orchestration/create_local_image_test/main_test.go | 2 +- .../host_orchestrator/orchestrator/listcvdsaction_test.go | 8 ++++---- frontend/src/libhoclient/fake_host_orchestrator_client.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/e2etests/orchestration/create_from_images_zip_test/main_test.go b/e2etests/orchestration/create_from_images_zip_test/main_test.go index d15b6243234..72fb5fc637a 100644 --- a/e2etests/orchestration/create_from_images_zip_test/main_test.go +++ b/e2etests/orchestration/create_from_images_zip_test/main_test.go @@ -90,7 +90,7 @@ func TestCreateInstance(t *testing.T) { Group: "foo", Name: "1", Status: "Running", - Displays: []string{"720 x 1280 ( 320 )"}, + Displays: []string{"720 x 1348 ( 280 )"}, WebRTCDeviceID: "cvd-1", ADBSerial: "127.0.0.1:6520", ADBPort: 6520, diff --git a/e2etests/orchestration/create_local_image_test/main_test.go b/e2etests/orchestration/create_local_image_test/main_test.go index 625effd8347..231c045c62a 100644 --- a/e2etests/orchestration/create_local_image_test/main_test.go +++ b/e2etests/orchestration/create_local_image_test/main_test.go @@ -98,7 +98,7 @@ func TestInstance(t *testing.T) { Group: group_name, Name: "1", Status: "Running", - Displays: []string{"720 x 1280 ( 320 )"}, + Displays: []string{"720 x 1348 ( 280 )"}, WebRTCDeviceID: "cvd-1", ADBSerial: "127.0.0.1:6520", ADBPort: 6520, diff --git a/frontend/src/host_orchestrator/orchestrator/listcvdsaction_test.go b/frontend/src/host_orchestrator/orchestrator/listcvdsaction_test.go index 06da3f28e3c..ffd0e447459 100644 --- a/frontend/src/host_orchestrator/orchestrator/listcvdsaction_test.go +++ b/frontend/src/host_orchestrator/orchestrator/listcvdsaction_test.go @@ -41,7 +41,7 @@ func TestListCVDsSucceeds(t *testing.T) { "adb_serial": "0.0.0.0:6520", "assembly_dir": "/var/lib/cuttlefish-common/runtimes/cuttlefish/assembly", "displays": [ - "720 x 1280 ( 320 )" + "720 x 1348 ( 280 )" ], "instance_dir": "/var/lib/cuttlefish-common/runtimes/cuttlefish/instances/cvd-1", "instance_name": "1", @@ -60,7 +60,7 @@ func TestListCVDsSucceeds(t *testing.T) { "adb_serial": "0.0.0.0:6520", "assembly_dir": "/var/lib/cuttlefish-common/runtimes/cuttlefish/assembly", "displays": [ - "720 x 1280 ( 320 )" + "720 x 1348 ( 280 )" ], "instance_dir": "/var/lib/cuttlefish-common/runtimes/cuttlefish/instances/cvd-1", "instance_name": "1", @@ -87,7 +87,7 @@ func TestListCVDsSucceeds(t *testing.T) { Group: "foo", Name: "1", Status: "Running", - Displays: []string{"720 x 1280 ( 320 )"}, + Displays: []string{"720 x 1348 ( 280 )"}, WebRTCDeviceID: "cvd-1", ADBSerial: "0.0.0.0:6520", ADBPort: 6520, @@ -96,7 +96,7 @@ func TestListCVDsSucceeds(t *testing.T) { Group: "bar", Name: "1", Status: "Running", - Displays: []string{"720 x 1280 ( 320 )"}, + Displays: []string{"720 x 1348 ( 280 )"}, WebRTCDeviceID: "cvd-1", ADBSerial: "0.0.0.0:6520", ADBPort: 6520, diff --git a/frontend/src/libhoclient/fake_host_orchestrator_client.go b/frontend/src/libhoclient/fake_host_orchestrator_client.go index e6d217a6e6b..dc361786261 100644 --- a/frontend/src/libhoclient/fake_host_orchestrator_client.go +++ b/frontend/src/libhoclient/fake_host_orchestrator_client.go @@ -182,7 +182,7 @@ func (c *FakeHostOrchestratorClient) createFakeCVDs(total int) ([]*hoapi.CVD, er Group: fmt.Sprintf("cvd-%d", id), Name: fmt.Sprintf("%d", id), Status: "Running", - Displays: []string{"720 x 1280 (320)"}, + Displays: []string{"720 x 1348 ( 280 )"}, WebRTCDeviceID: fmt.Sprintf("cvd-%d-%d", id, id), ADBSerial: fmt.Sprintf("0.0.0.0:%d", 6520+id-1), } From f2224b1e113e28545bad503d7fce8bf6138ab287 Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Mon, 10 Aug 2026 16:31:22 +0000 Subject: [PATCH 35/52] emulated_camera_mplane: Add QVGA resolution support Add QVGA (320x240) to SUPPORTED_SIZES as this is required by Android Camera2 CTS test testAvailableStreamConfigs. Bug: 534454250 Test: atest CtsCameraTestCases:android.hardware.camera2.cts. ExtendedCameraCharacteristicsTest#testAvailableStreamConfigs --- .../vhost_user_media/emulated_camera_mplane/src/device.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs index 9e3a2e61fe2..42f0b7af7df 100644 --- a/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs +++ b/base/cvd/cuttlefish/host/commands/vhost_user_media/emulated_camera_mplane/src/device.rs @@ -514,7 +514,8 @@ const WIDTH: u32 = 640; const HEIGHT: u32 = 480; const FRAME_RATE: u32 = 30; -const SUPPORTED_SIZES: [(u32, u32); 2] = [ +const SUPPORTED_SIZES: [(u32, u32); 3] = [ + (320, 240), (640, 480), (1280, 720), ]; From 77be4fb2dfbd810e3ed74bee9b4c2ba07a5b1180 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Fri, 24 Jul 2026 16:44:40 +0000 Subject: [PATCH 36/52] Security kernels don't get installed unless dist-upgrade is run. Assisted-By: Antigravity:Gemini-Next Bug: b/538688547 --- .../pkg/gce/scripts/install_kernel_main.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh b/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh index 0bfa854c367..73d1fe49653 100644 --- a/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh +++ b/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh @@ -34,7 +34,7 @@ version=$(sudo chroot /mnt/image/ /usr/bin/dpkg -s linux-image-cloud-${arch} | g echo "START VERSION: ${version}" sudo chroot /mnt/image /usr/bin/apt-get update -sudo chroot /mnt/image /usr/bin/apt-get upgrade -y +sudo chroot /mnt/image /usr/bin/apt-get dist-upgrade -y version=$(sudo chroot /mnt/image/ /usr/bin/dpkg -s linux-image-cloud-${arch} | grep ^Depends: | \ cut -d: -f2 | cut -d" " -f2 ) @@ -52,6 +52,20 @@ if [ "${version}" != "${linux_image_deb}" ]; then exit 1 fi +# Remove old kernel packages, keeping only the target kernel and the +# linux-image-cloud-${arch} meta-package. +old_kernels=$(sudo chroot /mnt/image /usr/bin/dpkg -l | grep '^ii' | awk '{print $2}' | \ + grep '^linux-image-' | grep -v "^${linux_image_deb}$" | grep -v "^linux-image-cloud-${arch}$" || true) +if [ -n "${old_kernels}" ]; then + echo "Removing old kernel packages: ${old_kernels}" + sudo chroot /mnt/image /usr/bin/apt-get purge -y ${old_kernels} + # update-grub may fail in a chroot; the grub config will be rebuilt + # when the image boots, so this is non-fatal. + sudo chroot /mnt/image /bin/sh -c 'command -v update-grub >/dev/null && update-grub || true' +else + echo "No old kernel packages to remove" +fi + # Skip unmounting: # Sometimes systemd starts, making it hard to unmount # In any case we'll unmount cleanly when the instance shuts down From 205659ebf1f03bc4e920df5d4acf9e0083aa3d39 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Fri, 31 Jul 2026 23:30:43 +0100 Subject: [PATCH 37/52] gigabyte-ampere-cuttlefish-installer: stop preinstalling kernels in the preseed check environment The check container installed linux-image-arm64 and linux-headers-arm64 from the live trixie/trixie-security archives. Real installer targets never have trixie headers, and their presence makes DKMS build the pinned NVIDIA driver against whatever kernel trixie-security shipped that day - an unpinned moving target. This broke on 2026-07-31 when Debian published 6.12.100, which the 550.163.01 driver fails to compile against, failing the nvidia matrix cell. With no stray kernels the block under test provides its own pinned kernel and DKMS builds only against the pinned, snapshot-frozen headers. Verified: the failing cell reproduced against 6.12.100 headers, and the same block passes with them absent (module builds and installs for 6.18.15). Bug: 537008147 Signed-off-by: Dmitrii Merkurev --- .../action.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/gigabyte-ampere-cuttlefish-installer-check-preseed-after-install-script/action.yaml b/.github/actions/gigabyte-ampere-cuttlefish-installer-check-preseed-after-install-script/action.yaml index f31c36df9a1..83c81bf2419 100644 --- a/.github/actions/gigabyte-ampere-cuttlefish-installer-check-preseed-after-install-script/action.yaml +++ b/.github/actions/gigabyte-ampere-cuttlefish-installer-check-preseed-after-install-script/action.yaml @@ -23,7 +23,6 @@ runs: apt-get install -y lsb-release apt-get install -y pciutils apt-get install -y apt-show-versions - apt-get install -y linux-image-arm64 linux-headers-arm64 - name: Setup base and non-free repository shell: bash run: | From cd4a333d09bae1472d3e0977efe1adbabf6cfae9 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Tue, 4 Aug 2026 14:11:14 +0100 Subject: [PATCH 38/52] gigabyte-ampere-cuttlefish-installer: pin the workflow actions The workflow still referenced actions by tag, which the zizmor blanket policy rejects as soon as the file is touched. Pin them to the hashes the tags currently point at, keeping the same major versions so the artifact upload and download stay compatible. Bug: 537008147 Signed-off-by: Dmitrii Merkurev --- .../gigabyte-ampere-cuttlefish-installer.yaml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml b/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml index 8e52f6694db..e9e65c0ed0d 100644 --- a/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml +++ b/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml @@ -56,7 +56,7 @@ jobs: nvidia_gpu: ["true", "false"] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Check preseed after install script uses: ./.github/actions/gigabyte-ampere-cuttlefish-installer-check-preseed-after-install-script with: @@ -72,11 +72,11 @@ jobs: image: debian@sha256:13f29b6806e531c3ff3b565bb6eed73f2132506c8c9d41bb996065ca20fb27f2 # debian:trixie-20260223 (amd64) steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Build iso installer uses: ./.github/actions/build-gigabyte-ampere-cuttlefish-installer - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts path: gigabyte-ampere-cuttlefish-installer/preseed-mini.iso.xz @@ -93,9 +93,9 @@ jobs: TEST_DISK_SIZE: "10G" steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment @@ -137,9 +137,9 @@ jobs: working-directory: ./gigabyte-ampere-cuttlefish-installer steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment @@ -185,9 +185,9 @@ jobs: working-directory: ./gigabyte-ampere-cuttlefish-installer steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment @@ -233,9 +233,9 @@ jobs: working-directory: ./gigabyte-ampere-cuttlefish-installer steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment @@ -281,9 +281,9 @@ jobs: working-directory: ./gigabyte-ampere-cuttlefish-installer steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment @@ -361,9 +361,9 @@ jobs: working-directory: ./gigabyte-ampere-cuttlefish-installer steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: gigabyte-ampere-cuttlefish-installer-artifacts - name: Prepare test environment From f9b612d3e60074f2b2d54d8953589c4a74840027 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Tue, 4 Aug 2026 14:11:14 +0100 Subject: [PATCH 39/52] gigabyte-ampere-cuttlefish-installer: wait for the vm to finish booting The qemu test jobs treat the serial console login prompt as "vm is ready" and ssh into the guest right away. The prompt only means getty started: the guest is still booting, so the ssh handshake gets reset (kex_exchange_identification: read: Connection reset by peer) and, once that is past, dns is not up yet for the first command needing it. The console is polled every 30s, so the ssh always lands at the same point after boot and whether it works is luck. Four of twelve job instances across six recent runs failed this way, on both jobs and regardless of which kernel the installer had put on the vm. Wait until systemd reports the boot finished before using the vm. Bug: 537008147 Signed-off-by: Dmitrii Merkurev --- .github/workflows/gigabyte-ampere-cuttlefish-installer.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml b/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml index e9e65c0ed0d..32ef8127919 100644 --- a/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml +++ b/.github/workflows/gigabyte-ampere-cuttlefish-installer.yaml @@ -301,6 +301,9 @@ jobs: run: | screen -d -m -L -Logfile console_001.log ./installer-iso-run-qemu.sh while ! egrep "[^[:space:]]+[[:space:]]login:" console_001.log; do sleep 30; done + # The login prompt appears before the system is usable, so wait for the + # boot to complete. "degraded" means booted with some unit failed. + until sshpass -p cuttlefish ssh -o "StrictHostKeyChecking no" -o "UserKnownHostsFile /dev/null" -o "ConnectTimeout 60" -p 33322 vsoc-01@localhost 'systemctl is-system-running | grep -qE "running|degraded"'; do sleep 30; done cp -f console_001.log console_001_p1.log CONSOLELINES=$(cat console_001_p1.log | wc -l) cat console_001_p1.log @@ -381,6 +384,9 @@ jobs: run: | screen -d -m -L -Logfile console_001.log ./installer-iso-run-qemu.sh while ! egrep "[^[:space:]]+[[:space:]]login:" console_001.log; do sleep 30; done + # The login prompt appears before the system is usable, so wait for the + # boot to complete. "degraded" means booted with some unit failed. + until sshpass -p cuttlefish ssh -o "StrictHostKeyChecking no" -o "UserKnownHostsFile /dev/null" -o "ConnectTimeout 60" -p 33322 vsoc-01@localhost 'systemctl is-system-running | grep -qE "running|degraded"'; do sleep 30; done cp -f console_001.log console_001_p1.log CONSOLELINES=$(cat console_001_p1.log | wc -l) cat console_001_p1.log From a35b667f585c8f3668332fd56b0b6912b72c3d27 Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Tue, 4 Aug 2026 14:34:08 -0400 Subject: [PATCH 40/52] Avoid dist-upgrade for now. * dist-upgrade will install the latest kernel package available disregaring the value of flag -linux-image-deb. * Follow up: make -linux-image-deb optional and then use "dist-upgrade" --- tools/baseimage/pkg/gce/scripts/install_kernel_main.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh b/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh index 73d1fe49653..363fe9513ac 100644 --- a/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh +++ b/tools/baseimage/pkg/gce/scripts/install_kernel_main.sh @@ -34,7 +34,7 @@ version=$(sudo chroot /mnt/image/ /usr/bin/dpkg -s linux-image-cloud-${arch} | g echo "START VERSION: ${version}" sudo chroot /mnt/image /usr/bin/apt-get update -sudo chroot /mnt/image /usr/bin/apt-get dist-upgrade -y +sudo chroot /mnt/image /usr/bin/apt-get upgrade -y version=$(sudo chroot /mnt/image/ /usr/bin/dpkg -s linux-image-cloud-${arch} | grep ^Depends: | \ cut -d: -f2 | cut -d" " -f2 ) From b57b9bca810abdd1246daa93e066ac6ba9c68834 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Tue, 4 Aug 2026 19:09:37 +0000 Subject: [PATCH 41/52] Add a wait for boot on kernel base image creation --- tools/baseimage/pkg/gce/gce.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/baseimage/pkg/gce/gce.go b/tools/baseimage/pkg/gce/gce.go index 9093424dc6f..cd26abed16d 100644 --- a/tools/baseimage/pkg/gce/gce.go +++ b/tools/baseimage/pkg/gce/gce.go @@ -295,6 +295,12 @@ func (h *GceHelper) BuildImage(project, zone string, opts BuildImageOpts) error defer h.cleanupDetachDisk(insName, attachedDiskName) log.Println("disk attached") + log.Println("waiting for instance to become responsive over SSH...") + if err := WaitForInstance(project, zone, insName); err != nil { + return fmt.Errorf("instance failed to become responsive over SSH: %w", err) + } + log.Println("instance is responsive over SSH") + if err := UploadBashScript(project, zone, insName, "fill_available_disk_space.sh", scripts.FillAvailableDiskSpace); err != nil { return fmt.Errorf("error uploading script: %v", err) } From 3e28f1921f09e3362cb0b5b3763610b3fb00bf83 Mon Sep 17 00:00:00 2001 From: Dmitrii Merkurev Date: Wed, 5 Aug 2026 01:35:00 +0100 Subject: [PATCH 42/52] gigabyte-ampere-cuttlefish-installer: resolve the build id via status.json The /builds/latest/ redirect the script followed is rate limited and returns 403 once the quota is exhausted, failing the download. Read the id from the target's status.json instead, which is not on that quota, and build the artifact URLs from it directly. Bug: 537008147 Signed-off-by: Dmitrii Merkurev --- .../utils/download-ci-cf.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh b/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh index 3872c447c5a..62d1594b175 100755 --- a/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh +++ b/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh @@ -4,11 +4,11 @@ set -o errexit -URL=https://ci.android.com/builds/latest/branches/aosp-android-latest-release/targets/aosp_cf_arm64_only_phone-userdebug/view/BUILD_INFO -RURL=$(curl -Ls -o /dev/null -w %{url_effective} ${URL}) -echo "RURL = ${RURL}" - -BUILD_ID=$(echo "${RURL}" | sed -n 's/.*\/builds\/submitted\/\([^\/]*\)\/.*/\1/p') +BRANCH=aosp-android-latest-release +TARGET=aosp_cf_arm64_only_phone-userdebug +BUILD_ID=$(curl -fsS \ + "https://ci.android.com/builds/branches/${BRANCH}/targets/${TARGET}/status.json" \ + | sed -n 's/.*[{,[:space:]]"last_known_good_build"[[:space:]]*:[[:space:]]*"\([0-9][0-9]*\)".*/\1/p') echo "BUILD_ID = ${BUILD_ID}" if [[ -z "${BUILD_ID}" ]]; then @@ -19,12 +19,9 @@ fi FILENAME="aosp_cf_arm64_only_phone-img-${BUILD_ID}.zip" echo "FILENAME = ${FILENAME}" -if [[ -z "${FILENAME}" ]]; then - echo "Error: FILENAME empty." - exit 1 -fi +RAWURL="https://ci.android.com/builds/submitted/${BUILD_ID}/${TARGET}/latest/raw" -wget -nv -c ${RURL%/view/BUILD_INFO}/raw/${FILENAME} -wget -nv -c ${RURL%/view/BUILD_INFO}/raw/cvd-host_package.tar.gz +wget -nv -c ${RAWURL}/${FILENAME} +wget -nv -c ${RAWURL}/cvd-host_package.tar.gz exit 0 From 8e6f5af0aaaff77692b11b318c0b4745f88ee6fd Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Wed, 8 Jul 2026 11:45:34 +0000 Subject: [PATCH 43/52] Revert "Disable all Kokoro test cases which requires ab" This reverts commit 40aed894992b6c6d992dd3613fbd9bc1b5790545. --- tools/testutils/runcvde2etests.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/testutils/runcvde2etests.sh b/tools/testutils/runcvde2etests.sh index eeb06ae4533..6d674b6da5e 100755 --- a/tools/testutils/runcvde2etests.sh +++ b/tools/testutils/runcvde2etests.sh @@ -23,10 +23,6 @@ while getopts "g" opt; do esac done -# TODO(b/532409657): Disable all test cases requiring ab for a moment as -# they're not working. -bazel_test_tag_filter_arg+=",-requires_ab" - function gather_test_results() { # Don't immediately exit on error anymore set +e From c1902bfe2e637d470da53c4073c45cd1f7a119f0 Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Thu, 6 Aug 2026 00:26:29 +0000 Subject: [PATCH 44/52] tools/*/cw/Containerfile is now based on trixie --- tools/buildutils/cw/Containerfile | 8 +------- tools/testutils/cw/Containerfile | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/buildutils/cw/Containerfile b/tools/buildutils/cw/Containerfile index 7a75e0f7693..7827a94cf9f 100644 --- a/tools/buildutils/cw/Containerfile +++ b/tools/buildutils/cw/Containerfile @@ -1,16 +1,10 @@ -FROM mirror.gcr.io/library/debian:bookworm-20250811 AS base +FROM mirror.gcr.io/library/debian:13 AS base ENV DEBIAN_FRONTEND=noninteractive RUN apt update -y && apt upgrade -y RUN apt install -y sudo devscripts -# Download newer version of golang with keep using bookworm for building debian -# packages. -RUN echo "deb http://deb.debian.org/debian bookworm-backports main" > /etc/apt/sources.list.d/backports.list -RUN apt update -RUN apt install -t bookworm-backports -y golang - COPY ./tools/buildutils/installbazel.sh /installbazel.sh RUN /installbazel.sh && rm /installbazel.sh diff --git a/tools/testutils/cw/Containerfile b/tools/testutils/cw/Containerfile index e0afd83c939..99b8dfad03d 100644 --- a/tools/testutils/cw/Containerfile +++ b/tools/testutils/cw/Containerfile @@ -1,4 +1,4 @@ -FROM mirror.gcr.io/library/debian:bookworm-20250811 AS base +FROM mirror.gcr.io/library/debian:13 AS base ENV DEBIAN_FRONTEND=noninteractive ENV OVERRIDE_BAZEL_WRAPPER_DOWNLOAD_DIR=/tmp/cw_bazel From 55508264f25a3f814f9722cd8170de75b46ad162 Mon Sep 17 00:00:00 2001 From: Alex Carp Date: Thu, 25 Jun 2026 16:31:57 +0300 Subject: [PATCH 45/52] Override the default udev rule priority of debhelper, which is 60, to 88 This allows the udev rule of cuttlefish-base to be executed later Bug: 500283166 --- base/debian/rules | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/base/debian/rules b/base/debian/rules index 76868178722..c85518c9c3a 100755 --- a/base/debian/rules +++ b/base/debian/rules @@ -115,3 +115,9 @@ override_dh_fixperms: dh_fixperms chmod -x ${cuttlefish_common}/bin/*.json find ${cuttlefish_common}/etc -type f -exec chmod -x '{}' ';' + +# Override udev rule priority (default is 60) +.PHONY: override_dh_installudev +override_dh_installudev: + dh_installudev --package=cuttlefish-base --priority=88 + dh_installudev --remaining-packages From 4d7cf88b4dc3d17037cc5dcacf471b1b605140e9 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Thu, 9 Jul 2026 12:30:00 -0700 Subject: [PATCH 46/52] Use skiavk for hwui on gfxstream+angle based modes Bug: b/533056543 Test: bazel run //cuttlefish/package:cvd -- \ create \ --gpu_mode=gfxstream_guest_angle wait for boot `adb shell dumpsys gfxinfo | grep Pipeline` shows skia vulkan --- .../commands/assemble_cvd/graphics_flags.cc | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index b4a8aac7d91..e3d8d6f5b03 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -633,6 +633,35 @@ Result SelectGpuVhostUserMode(const GpuMode gpu_mode, return gpu_vhost_user_mode_arg == kGpuVhostUserModeOn; } +Result SelectGuestHwuiRenderer( + const GpuMode gpu_mode, const GuestConfig& guest_config, + const std::string& guest_hwui_renderer_arg) { + if (!guest_hwui_renderer_arg.empty()) { + GuestHwuiRenderer hwui_renderer = CF_EXPECT( + ParseGuestHwuiRenderer(guest_hwui_renderer_arg), + "Failed to parse HWUI renderer flag: " << guest_hwui_renderer_arg); + VLOG(0) << "Using explicitly provided HWUI renderer: " + << ToString(hwui_renderer); + return hwui_renderer; + } + + // Only makes sense for Android guests: + if (guest_config.android_version_number.empty()) { + return GuestHwuiRenderer::kUnknown; + } + + // TODO(b/533056543): after testing Gfxstream's virtual queue support. + if (IsGfxstreamGuestAngleMode(gpu_mode) && + gpu_mode != GpuMode::GfxstreamGuestAngleHostSwiftshader) { + VLOG(0) << "Selecting SkiaVk as the HWUI renderer for " + << GpuModeString(gpu_mode) + << " GPU mode which is GfxstreamGuestAngle* based."; + return GuestHwuiRenderer::kSkiaVk; + } + + return GuestHwuiRenderer::kUnknown; +} + Result SelectGuestRendererPreload( const GpuMode gpu_mode, const GuestHwuiRenderer guest_hwui_renderer, const std::string& guest_renderer_preload_arg) { @@ -648,8 +677,8 @@ Result SelectGuestRendererPreload( if (guest_hwui_renderer == GuestHwuiRenderer::kSkiaVk && (gpu_mode == GpuMode::GfxstreamGuestAngle || gpu_mode == GpuMode::GfxstreamGuestAngleHostSwiftshader)) { - LOG(INFO) << "Disabling guest renderer preload for Gfxstream based mode " - "when running with SkiaVk."; + VLOG(0) << "Disabling guest renderer preload for Gfxstream based mode " + "when running with SkiaVk."; guest_renderer_preload = GuestRendererPreload::kDisabled; } } @@ -704,7 +733,8 @@ std::string GetGfxstreamRendererFeaturesString( CF_UNUSED_ON_MACOS Result SetGfxstreamFlags( - const GpuMode gpu_mode, const std::string& gpu_renderer_features_arg, + const GpuMode gpu_mode, const GuestHwuiRenderer hwui_renderer, + const std::string& gpu_renderer_features_arg, const GuestConfig& guest_config, const gfxstream::proto::GraphicsAvailability& availability, CuttlefishConfig::MutableInstanceSpecific& instance) { @@ -728,6 +758,13 @@ Result SetGfxstreamFlags( features["GlProgramBinaryLinkStatus"] = true; } + // SwiftShader currently only supports a single queue. SkiaVK requests + // a second queue used for transfers. + if (gpu_mode == GpuMode::GfxstreamGuestAngleHostSwiftshader && + hwui_renderer == GuestHwuiRenderer::kSkiaVk) { + features["VulkanVirtualQueue"] = true; + } + // Apply feature overrides from --gpu_renderer_features. const auto feature_overrides = CF_EXPECT(ParseGfxstreamRendererFlag(gpu_renderer_features_arg)); @@ -834,11 +871,6 @@ Result ConfigureGpuSettings( const bool enable_gpu_vhost_user = CF_EXPECT(SelectGpuVhostUserMode(gpu_mode, gpu_vhost_user_mode_arg, vmm)); - if (IsGfxstreamMode(gpu_mode)) { - CF_EXPECT(SetGfxstreamFlags(gpu_mode, gpu_renderer_features_arg, - guest_config, graphics_availability, instance)); - } - if (gpu_mode == GpuMode::Custom) { std::vector requested_types = absl::StrSplit(gpu_context_types_arg, ':'); @@ -867,18 +899,20 @@ Result ConfigureGpuSettings( instance.set_enable_gpu_system_blob(false); } - GuestHwuiRenderer hwui_renderer = GuestHwuiRenderer::kUnknown; - if (!guest_hwui_renderer_arg.empty()) { - hwui_renderer = CF_EXPECT( - ParseGuestHwuiRenderer(guest_hwui_renderer_arg), - "Failed to parse HWUI renderer flag: " << guest_hwui_renderer_arg); - } + const GuestHwuiRenderer hwui_renderer = CF_EXPECT( + SelectGuestHwuiRenderer(gpu_mode, guest_config, guest_hwui_renderer_arg)); instance.set_guest_hwui_renderer(hwui_renderer); const auto guest_renderer_preload = CF_EXPECT(SelectGuestRendererPreload( gpu_mode, hwui_renderer, guest_renderer_preload_arg)); instance.set_guest_renderer_preload(guest_renderer_preload); + if (IsGfxstreamMode(gpu_mode)) { + CF_EXPECT(SetGfxstreamFlags(gpu_mode, hwui_renderer, + gpu_renderer_features_arg, guest_config, + graphics_availability, instance)); + } + instance.set_gpu_mode(gpu_mode); instance.set_enable_gpu_vhost_user(enable_gpu_vhost_user); From c761459e8c4f3eab7efc430adb8c0509afab6c7b Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 22 Jul 2026 07:49:04 -0700 Subject: [PATCH 47/52] Update graphics availability logging to avoid truncation ... as these logs are valuable for debugging issues like b/537569893 Bug: b/537569893 Test: bazel run //cuttlefish/package:cvd -- create --- .../host/commands/assemble_cvd/graphics_flags.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index e3d8d6f5b03..97ad63ddf77 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -832,7 +832,12 @@ GetGraphicsAvailabilityWithSubprocessCheck() { return {}; } - VLOG(0) << "Host Graphics Availability:" << availability.DebugString(); + VLOG(0) << "Host Graphics Availability:"; + for (absl::string_view line : + absl::StrSplit(graphics_availability_content, '\n')) { + VLOG(0) << line; + } + return availability; #endif } From ee401749f9c714492385a96209a607fcbd3fea85 Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 22 Jul 2026 07:51:15 -0700 Subject: [PATCH 48/52] Enable multi queue emulation when needed for hwui on skiavk HWUI's vulkan setup requires 2 queues which may not always be supported by the hosts vulkan driver. Gfxstream has a mode to emulate this support. This change updates the launcher to try to detect when this is needed and enable the feature if so. Bug: b/537569893 Test: bazel run //cuttlefish/package:cvd -- create --- .../commands/assemble_cvd/graphics_flags.cc | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index 97ad63ddf77..6c6bdf098cb 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -731,6 +731,28 @@ std::string GetGfxstreamRendererFeaturesString( return absl::StrJoin(parts, ","); } +CF_UNUSED_ON_MACOS +bool HasMultipleGraphicsQueues( + const gfxstream::proto::GraphicsAvailability& availability) { + if (!availability.has_vulkan()) { + return false; + } + const gfxstream::proto::VulkanAvailability& vulkan_availability = + availability.vulkan(); + if (vulkan_availability.physical_devices().empty()) { + return false; + } + const auto& physical_device = vulkan_availability.physical_devices(0); + for (const auto& queue_family : physical_device.queue_families()) { + if (!queue_family.has_supports_graphics()) continue; + if (!queue_family.supports_graphics()) continue; + + // HWUI seems to only check the first queue family supporting graphics: + return queue_family.has_queue_count() && queue_family.queue_count() >= 2; + } + return false; +} + CF_UNUSED_ON_MACOS Result SetGfxstreamFlags( const GpuMode gpu_mode, const GuestHwuiRenderer hwui_renderer, @@ -758,11 +780,21 @@ Result SetGfxstreamFlags( features["GlProgramBinaryLinkStatus"] = true; } - // SwiftShader currently only supports a single queue. SkiaVK requests - // a second queue used for transfers. - if (gpu_mode == GpuMode::GfxstreamGuestAngleHostSwiftshader && - hwui_renderer == GuestHwuiRenderer::kSkiaVk) { - features["VulkanVirtualQueue"] = true; + if (hwui_renderer == GuestHwuiRenderer::kSkiaVk) { + // SkiaVK requires a second graphics queue for AHB transfers. + const bool needs_multi_queue_emulation = + (gpu_mode == GpuMode::GfxstreamGuestAngleHostSwiftshader) + ? + // The SwiftShader driver packaged with the Cuttlefish host tools + // does not appear in `availability` and does not have multiple + // queues. + true + : !HasMultipleGraphicsQueues(availability); + ; + + if (needs_multi_queue_emulation) { + features["VulkanVirtualQueue"] = true; + } } // Apply feature overrides from --gpu_renderer_features. From 118b1d5c4af70cb9ad793a80e3f0807effedab0d Mon Sep 17 00:00:00 2001 From: Jason Macnak Date: Wed, 1 Jul 2026 16:56:46 -0700 Subject: [PATCH 49/52] Ignore unknown fields in graphics detector parsing ... to stay in sync with ag/40769486. Also, adds error collecting to potentially help in the future. Bug: b/530288420 Test: cvd create --- .../host/commands/assemble_cvd/BUILD.bazel | 1 + .../commands/assemble_cvd/graphics_flags.cc | 29 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel b/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel index 0f006b2aecb..379634a7036 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/BUILD.bazel @@ -458,6 +458,7 @@ cf_cc_library( "@abseil-cpp//absl/strings", "@fmt", "@protobuf", + "@protobuf//src/google/protobuf/io:tokenizer", ], ) diff --git a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc index 6c6bdf098cb..12ac1df4a90 100644 --- a/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc +++ b/base/cvd/cuttlefish/host/commands/assemble_cvd/graphics_flags.cc @@ -21,12 +21,13 @@ #include #include -#include "absl/strings/str_join.h" -#include -#include #include "absl/log/log.h" #include "absl/strings/ascii.h" +#include "absl/strings/str_join.h" #include "absl/strings/str_split.h" +#include +#include +#include #include "cuttlefish/common/libs/utils/contains.h" #include "cuttlefish/common/libs/utils/files.h" @@ -52,6 +53,23 @@ namespace cuttlefish { namespace { +struct AggregatingErrorCollector : public google::protobuf::io::ErrorCollector { + void RecordError(int /* line */, int /* column */, + const absl::string_view message) override { + if (!error_message.empty()) { + absl::StrAppend(&error_message, "; "); + } + absl::StrAppend(&error_message, message); + } + + void RecordWarning(int /* line */, int /* column */, + const absl::string_view /* message */) override { + // Ignore warnings + } + + std::string error_message; +}; + struct CommonState { const VmmMode vmm_mode; const GuestConfig& guest_config; @@ -856,10 +874,15 @@ GetGraphicsAvailabilityWithSubprocessCheck() { graphics_availability_content_result.value(); gfxstream::proto::GraphicsAvailability availability; + google::protobuf::TextFormat::Parser parser; + parser.AllowUnknownField(true); + AggregatingErrorCollector error_collector; + parser.RecordErrorsTo(&error_collector); if (!parser.ParseFromString(graphics_availability_content, &availability)) { LOG(ERROR) << "Failed to parse graphics detector output: " << graphics_availability_content + << ". Error(s): " << error_collector.error_message << ". Assuming no availability."; return {}; } From 31ef0f57d5740cb690266270ad3bc1403403741e Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Wed, 24 Jun 2026 04:53:21 +0000 Subject: [PATCH 50/52] Update container image into trixie --- container/image/Containerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/container/image/Containerfile b/container/image/Containerfile index 6b058d9d2ef..59081615bad 100644 --- a/container/image/Containerfile +++ b/container/image/Containerfile @@ -5,7 +5,7 @@ ARG BUILD_OPTION=prod -FROM mirror.gcr.io/library/debian:12 AS runner-base +FROM mirror.gcr.io/library/debian:13 AS runner-base # Expose Operator Port (HTTP:1080, HTTPS:1443) EXPOSE 1080 1443 From 488980829a371267db6bf2e49651cf6384a9e137 Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Wed, 24 Jun 2026 02:10:20 +0000 Subject: [PATCH 51/52] Container needs libvulkan1, not whole mesa-vulkan-drivers --- container/image/Containerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/container/image/Containerfile b/container/image/Containerfile index 59081615bad..2d218e5fbff 100644 --- a/container/image/Containerfile +++ b/container/image/Containerfile @@ -26,6 +26,7 @@ RUN apt update RUN apt install -y --no-install-recommends \ ca-certificates \ curl \ + libvulkan1 \ mesa-utils \ nginx \ sudo From e87b1addc6def7cbab697d0f492912c24ce85688 Mon Sep 17 00:00:00 2001 From: Seungjae Yoo Date: Thu, 25 Jun 2026 04:08:02 +0000 Subject: [PATCH 52/52] Way of downloading debs on container should be compatible to trixie --- container/image/Containerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/container/image/Containerfile b/container/image/Containerfile index 2d218e5fbff..bcc74670df1 100644 --- a/container/image/Containerfile +++ b/container/image/Containerfile @@ -60,10 +60,11 @@ RUN apt install -y --no-install-recommends -f \ FROM runner-base AS runner-prod ARG REPO -RUN apt install -y --no-install-recommends gnupg -RUN curl https://us-apt.pkg.dev/doc/repo-signing-key.gpg | apt-key add - -RUN echo "deb https://us-apt.pkg.dev/projects/android-cuttlefish-artifacts $REPO main" \ - | tee -a /etc/apt/sources.list.d/artifact-registry.list +RUN install -m 0755 -d /etc/apt/keyrings +RUN curl -fsSL https://us-apt.pkg.dev/doc/repo-signing-key.gpg -o /etc/apt/keyrings/android-cuttlefish-artifacts.asc +RUN chmod a+r /etc/apt/keyrings/android-cuttlefish-artifacts.asc +RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/android-cuttlefish-artifacts.asc] https://us-apt.pkg.dev/projects/android-cuttlefish-artifacts $REPO main" \ + | tee /etc/apt/sources.list.d/android-cuttlefish-artifacts.list > /dev/null RUN apt update RUN apt install -y --no-install-recommends \ cuttlefish-base \