From fdac31510e0ac0a206141e56f1b210e7d59d6f52 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 23 Jul 2026 01:40:34 +0000 Subject: [PATCH 01/13] modem_simulator: prevent unhandled exceptions for strings shorter than 2 std::string::compare > The overloads taking parameters named pos1 or pos2 > throws std::out_of_range if the argument is out of range. Bug: 509614113 Signed-off-by: Roman Kiryanov --- .../host/commands/modem_simulator/modem_service.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/modem_service.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/modem_service.cpp index 54151593be2..e5806c32371 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/modem_service.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/modem_service.cpp @@ -34,14 +34,13 @@ CommandHandler::CommandHandler(const std::string& command, p_func handler) p_command_handler(handler) {} int CommandHandler::Compare(const std::string& command) const { - int result = -1; - if (match_mode == PARTIAL_MATCH) { - result = - command.compare(2, command_prefix.size(), command_prefix); // skip "AT" - } else { - result = command.compare(2, command.size(), command_prefix); + if (command.size() < 2) { // the "AT" prefix + return -1; } - return result; + + return (match_mode == PARTIAL_MATCH) + ? command.compare(2, command_prefix.size(), command_prefix) + : command.compare(2, command.size(), command_prefix); } void CommandHandler::HandleCommand(const Client& client, From 6b71522288f9011204c9758ed5f35b704f270831 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 23 Jul 2026 17:20:45 +0000 Subject: [PATCH 02/13] modem_simulator: prevent unhandled exceptions for incorrect input std::stoi: > std::invalid_argument if no conversion could be performed. > std::out_of_range if the converted value would fall out of the range Bug: 509614113 Signed-off-by: Roman Kiryanov --- .../cuttlefish/host/commands/modem_simulator/call_service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/call_service.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/call_service.cpp index 554878d4ff0..248ca45b5c6 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/call_service.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/call_service.cpp @@ -400,8 +400,8 @@ void CallService::HandleHangup(const Client& client, CommandParser cmd(command); cmd.SkipPrefix(); - std::string action(*cmd); - int n = std::stoi(action.substr(0, 1)); + const std::string action(*cmd); + const int n = action.empty() ? -1 : (action[0] - '0'); int index = -1; if (cmd->length() > 1) { index = std::stoi(action.substr(1)); From 3888b14eff02b9fc27b51979aa7193cbbafc7efe Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 23 Jul 2026 17:28:59 +0000 Subject: [PATCH 03/13] modem_simulator: fix the possible OOB if the buffer is not null terminated If the `Read` call fills the whole buffer, `commands.append(buffer.data())` with no zero characters will read past the buffer. If the `Read` produces data with zero characters in the middle, it will cause a loss of data. Bug: 509614113 Signed-off-by: Roman Kiryanov --- .../commands/modem_simulator/channel_monitor.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/channel_monitor.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/channel_monitor.cpp index b8f64818680..5a68a543993 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/channel_monitor.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/channel_monitor.cpp @@ -81,8 +81,8 @@ void ChannelMonitor::AcceptIncomingConnection() { } void ChannelMonitor::ReadCommand(Client& client) { - std::vector buffer(kMaxCommandLength); - auto bytes_read = client.client_read_fd_->Read(buffer.data(), buffer.size()); + char buffer[kMaxCommandLength]; + auto bytes_read = client.client_read_fd_->Read(buffer, kMaxCommandLength); if (bytes_read <= 0) { if (errno == EAGAIN && client.type == Client::REMOTE && client.first_read_command_) { @@ -105,13 +105,9 @@ void ChannelMonitor::ReadCommand(Client& client) { return; } - std::string& incomplete_command = client.incomplete_command; - // Add the incomplete command from the last read - auto commands = std::string{incomplete_command.data()}; - commands.append(buffer.data()); - - incomplete_command.clear(); + std::string commands(std::move(client.incomplete_command)); + commands.append(buffer, bytes_read); // Replacing '\n' with '\r' absl::StrReplaceAll({{"\n", "\r"}}, &commands); @@ -132,8 +128,8 @@ void ChannelMonitor::ReadCommand(Client& client) { } pos = r_pos + 1; // Skip '\r' } else if (pos < commands.length()) { // Incomplete command - incomplete_command = commands.substr(pos); - VLOG(1) << "incomplete command: " << incomplete_command; + client.incomplete_command = commands.substr(pos); + VLOG(1) << "incomplete command: " << client.incomplete_command; } } } From c9c99abee656ee60b1b0f7eb25ca962ebbab8540 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 23 Jul 2026 19:29:54 +0000 Subject: [PATCH 04/13] modem_simulator: avoid referring to a dead object The `sms_pdu` is used in an async callback, potentially after the control leaves the scope. Bug: 509614113 Signed-off-by: Roman Kiryanov --- .../cuttlefish/host/commands/modem_simulator/sms_service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/cvd/cuttlefish/host/commands/modem_simulator/sms_service.cpp b/base/cvd/cuttlefish/host/commands/modem_simulator/sms_service.cpp index 166868c66ca..5068ca18880 100644 --- a/base/cvd/cuttlefish/host/commands/modem_simulator/sms_service.cpp +++ b/base/cvd/cuttlefish/host/commands/modem_simulator/sms_service.cpp @@ -297,7 +297,7 @@ void SmsService::HandleSendSMSPDU(const Client& client, std::string& command) { thread_looper_->Post( makeSafeCallback( this, - [&sms_pdu](SmsService* me) { me->HandleReceiveSMS(sms_pdu); }), + [sms_pdu](SmsService* me) { me->HandleReceiveSMS(sms_pdu); }), std::chrono::seconds(1)); } else { // Send SMS to remote host port SendSmsToRemote(remote_host_port, sms_pdu); From f0555592d7d0e06778c39298db754e2a3346858f Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Sat, 18 Jul 2026 21:51:14 -0300 Subject: [PATCH 05/13] gigabyte-ampere-cuttlefish-installer: utils: download-ci-cf.sh: use JSON API The previous way to download the artifacts doesn't work. We fix it by using the latest JSON API. And also make the script more verbose on error. Signed-off-by: Ying-Chun Liu (PaulLiu) --- .../utils/download-ci-cf.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh b/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh index 22f5162b01a..3872c447c5a 100755 --- a/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh +++ b/gigabyte-ampere-cuttlefish-installer/utils/download-ci-cf.sh @@ -6,9 +6,23 @@ 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 +echo "RURL = ${RURL}" -FILENAME=$(wget -nv -O - ${RURL%/view/BUILD_INFO}/ | grep aosp_cf_arm64_only_phone-img- | sed 's/.*\(aosp_cf_arm64_only_phone-img-[0-9]*[.]zip\).*/\1/g') +BUILD_ID=$(echo "${RURL}" | sed -n 's/.*\/builds\/submitted\/\([^\/]*\)\/.*/\1/p') +echo "BUILD_ID = ${BUILD_ID}" + +if [[ -z "${BUILD_ID}" ]]; then + echo "Error: BUILD_ID empty." + exit 1 +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 wget -nv -c ${RURL%/view/BUILD_INFO}/raw/${FILENAME} wget -nv -c ${RURL%/view/BUILD_INFO}/raw/cvd-host_package.tar.gz From 205e1f48eb691a1e6f86875f9dc57f06d322c485 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 16 Jul 2026 14:19:22 -0700 Subject: [PATCH 06/13] Fix dependency issues with fetch:build_api_credentials Bug: b/534499070 --- base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel | 2 +- .../cuttlefish/host/commands/cvd/fetch/build_api_credentials.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 5db93be1685..8f86437bd52 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -40,11 +40,11 @@ cf_cc_library( "//cuttlefish/common/libs/utils:files", "//cuttlefish/common/libs/utils:json", "//cuttlefish/host/commands/cvd/fetch:build_api_flags", - "//cuttlefish/host/commands/cvd/fetch:credential_flags", "//cuttlefish/host/libs/web:credential_source", "//cuttlefish/host/libs/web/http_client", "//cuttlefish/result", "@abseil-cpp//absl/log", + "@jsoncpp", ], ) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_credentials.cc b/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_credentials.cc index 48a174b2f54..053258b871a 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_credentials.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_credentials.cc @@ -20,6 +20,8 @@ #include #include "absl/log/log.h" +#include "json/reader.h" +#include "json/value.h" #include "cuttlefish/common/libs/utils/environment.h" #include "cuttlefish/common/libs/utils/files.h" From f923c93517d165d5a18dfb8396eb3c060d6dde94 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 16 Jul 2026 14:21:54 -0700 Subject: [PATCH 07/13] Fix dependency issues with fetch:build_api_flags Bug: b/534499070 --- base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel | 1 - base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_flags.cc | 1 - 2 files changed, 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 8f86437bd52..df24af71fb7 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -59,7 +59,6 @@ cf_cc_library( "//cuttlefish/host/libs/web:android_build_url", "//cuttlefish/host/libs/web/cas:cas_flags", "//cuttlefish/result", - "//libbase", "@abseil-cpp//absl/strings", ], ) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_flags.cc b/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_flags.cc index 07efbaadc3d..990a823ef6f 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_flags.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/build_api_flags.cc @@ -16,7 +16,6 @@ #include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h" #include -#include #include #include From f59138214a1f45ac356eec5d4669967d341d79b4 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 16 Jul 2026 14:25:03 -0700 Subject: [PATCH 08/13] Fix dependency issues with fetch:downloaders Bug: b/534499070 --- base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel | 2 -- base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc | 1 - base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.h | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index df24af71fb7..7a02064fb1c 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -126,9 +126,7 @@ cf_cc_library( "//cuttlefish/common/libs/utils:environment", "//cuttlefish/host/commands/cvd/fetch:build_api_credentials", "//cuttlefish/host/commands/cvd/fetch:build_api_flags", - "//cuttlefish/host/commands/cvd/fetch:fetch_cvd_parser", "//cuttlefish/host/libs/web:android_build_api", - "//cuttlefish/host/libs/web:android_build_api_key", "//cuttlefish/host/libs/web:android_build_url", "//cuttlefish/host/libs/web:build_api", "//cuttlefish/host/libs/web:caching_build_api", diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc b/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc index 2c421186284..be7bd1d77c7 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.cc @@ -23,7 +23,6 @@ #include "cuttlefish/common/libs/utils/environment.h" #include "cuttlefish/host/commands/cvd/fetch/build_api_credentials.h" #include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h" -#include "cuttlefish/host/commands/cvd/fetch/fetch_cvd_parser.h" #include "cuttlefish/host/libs/web/android_build_api.h" #include "cuttlefish/host/libs/web/android_build_url.h" #include "cuttlefish/host/libs/web/build_api.h" diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.h b/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.h index 83df7bfad2c..2d34c98d68f 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.h +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/downloaders.h @@ -18,7 +18,7 @@ #include #include -#include "cuttlefish/host/commands/cvd/fetch/fetch_cvd_parser.h" +#include "cuttlefish/host/commands/cvd/fetch/build_api_flags.h" #include "cuttlefish/host/libs/web/build_api.h" #include "cuttlefish/host/libs/web/luci_build_api.h" #include "cuttlefish/result/result.h" From ccadb9924aaad0881e9435774fcb5b77ee2e6593 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 16 Jul 2026 14:26:58 -0700 Subject: [PATCH 09/13] Fix build issues with fetch:fetch_context Bug: b/534499070 --- base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel | 2 -- 1 file changed, 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 7a02064fb1c..6525e4242c4 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -170,7 +170,6 @@ cf_cc_library( srcs = ["fetch_context.cc"], hdrs = ["fetch_context.h"], deps = [ - "//cuttlefish/common/libs/utils:archive", "//cuttlefish/common/libs/utils:files", "//cuttlefish/host/commands/cvd/fetch:builds", "//cuttlefish/host/commands/cvd/fetch:de_android_sparse", @@ -184,7 +183,6 @@ cf_cc_library( "//cuttlefish/host/libs/web:build_api_zip", "//cuttlefish/host/libs/zip:zip_file", "//cuttlefish/host/libs/zip/libzip_cc:archive", - "//cuttlefish/posix:strerror", "//cuttlefish/result", "//libbase", "@abseil-cpp//absl/strings", From 570531f46f562341ffb20affb24748c207cc7a99 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 16 Jul 2026 14:28:44 -0700 Subject: [PATCH 10/13] Fix dependency issues with fetch:fetch_cvd Bug: b/534499070 --- base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel | 2 -- 1 file changed, 2 deletions(-) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 6525e4242c4..97e7db26f57 100644 --- a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel +++ b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel @@ -209,7 +209,6 @@ cf_cc_library( "//cuttlefish/host/commands/cvd/fetch:fetch_tracer", "//cuttlefish/host/commands/cvd/fetch:host_package", "//cuttlefish/host/commands/cvd/fetch:host_tools_target", - "//cuttlefish/host/commands/cvd/fetch:substitute", "//cuttlefish/host/commands/cvd/fetch:target_directories", "//cuttlefish/host/commands/cvd/utils:common", "//cuttlefish/host/libs/config:fetcher_config", @@ -221,7 +220,6 @@ cf_cc_library( "//cuttlefish/host/libs/web:chrome_os_build_string", "//cuttlefish/host/libs/web:luci_build_api", "//cuttlefish/host/libs/web/http_client:curl_global_init", - "//cuttlefish/host/libs/zip:zip_string", "//cuttlefish/host/libs/zip/libzip_cc:archive", "//cuttlefish/io", "//cuttlefish/io:string", From 1e89e80daa5d7a93792c7e9b8a747a9d6b38522a Mon Sep 17 00:00:00 2001 From: Sergio Andres Rodriguez Orama Date: Mon, 27 Jul 2026 14:11:04 -0400 Subject: [PATCH 11/13] Emulate signal gain for emulated_camera_mplane. Interact with the control: ``` adb shell "su 0 v4l2-ctl -d /dev/video1 -l" adb shell "su 0 v4l2-ctl -d /dev/video1 --set-ctrl=gain=500" ``` Introduce CameraControls, to manage the state of control values. Bug: b/539617743 Assisted-by: Jetski:Gemini 3.5 Flash --- .../emulated_camera_mplane/src/device.rs | 330 ++++++++++++++++-- 1 file changed, 297 insertions(+), 33 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 d81245ac522..6986837e048 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 @@ -57,6 +57,14 @@ use virtio_media::protocol::V4l2Ioctl; use virtio_media::protocol::VIRTIO_MEDIA_MMAP_FLAG_RW; use std::str::FromStr; +/// Rust equivalent of the V4L2_CTRL_ID2WHICH C preprocessor macro. +/// Extracts the control class ID from a control ID by masking out the lower 16 bits +/// and any reserved top bits (uses mask 0x0fff0000). +/// See: https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/control.html +const fn v4l2_ctrl_id2which(id: u32) -> u32 { + id & 0x0fff0000 +} + /// https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#LENS_FACING_FRONT #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LensFacing { @@ -78,6 +86,49 @@ impl FromStr for LensFacing { } } +/// Encapsulates the camera gain value. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Gain(i32); + +impl Gain { + pub const MIN: i32 = 100; + pub const MAX: i32 = 1600; + pub const DEFAULT: i32 = 100; + + pub fn new(value: i32) -> Result { + if value < Self::MIN || value > Self::MAX { + Err(libc::ERANGE) + } else { + Ok(Gain(value)) + } + } + + pub fn value(&self) -> i32 { + self.0 + } +} + +impl Default for Gain { + fn default() -> Self { + Gain(Self::DEFAULT) + } +} + +/// State of all camera controls. +struct CameraControls { + lens_facing: LensFacing, + gain: Gain, +} + +impl CameraControls { + fn new(lens_facing: LensFacing) -> Self { + Self { + lens_facing, + gain: Gain::default(), + } + } +} + /// Current status of a buffer. #[derive(Debug, PartialEq, Eq)] enum BufferState { @@ -194,6 +245,7 @@ impl VirtioMediaDeviceSession for EmulatedCameraSession { impl EmulatedCameraSession { fn write_pattern( iteration: u64, + controls: &CameraControls, mut sink_y: WY, mut sink_u: WU, mut sink_v: WV, @@ -201,7 +253,12 @@ impl EmulatedCameraSession { let mut writer_y = BufWriter::new(&mut sink_y); let mut writer_u = BufWriter::new(&mut sink_u); let mut writer_v = BufWriter::new(&mut sink_v); - let y = (iteration % 256) as u8; + // The base Y (luma) value changes over iterations to create a moving pattern. + let base_y = (iteration % 256) as u8; + // Apply gain to the luma channel. + // Gain::MIN (100) represents 1.0x gain. Higher values scale the brightness. + // We clamp the result to 255.0 to avoid overflow. + 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) { @@ -220,6 +277,7 @@ impl EmulatedCameraSession { fn process_queued_buffers( &mut self, evt_queue: &mut Q, + controls: &CameraControls, ) -> IoctlResult<()> { while let Some(buf_id) = self.queued_buffers.pop_front() { let iteration = self.iteration; @@ -235,6 +293,7 @@ impl EmulatedCameraSession { Self::write_pattern( iteration, + controls, buffer.planes[0].fd.as_file(), buffer.planes[1].fd.as_file(), buffer.planes[2].fd.as_file(), @@ -271,8 +330,8 @@ pub struct EmulatedCamera, - /// Lens facing configuration. - lens_facing: LensFacing, + /// Camera controls. + controls: CameraControls, } impl EmulatedCamera @@ -285,7 +344,7 @@ where evt_queue, mmap_manager: MmapMappingManager::from(mapper), active_session: None, - lens_facing, + controls: CameraControls::new(lens_facing), } } @@ -300,13 +359,60 @@ where minimum: LensFacing::Front as i64, maximum: LensFacing::External as i64, step: 1, - default_value: self.lens_facing as i64, + default_value: self.controls.lens_facing as i64, flags: bindings::V4L2_CTRL_FLAG_READ_ONLY, elems: 1, elem_size: std::mem::size_of::() as u32, ..Default::default() } } + + fn gain_query_ext_ctrl(&self) -> bindings::v4l2_query_ext_ctrl { + let name_str = "Gain"; + let mut name = [0u8; 32]; + name[0..name_str.len()].copy_from_slice(name_str.as_bytes()); + bindings::v4l2_query_ext_ctrl { + id: bindings::V4L2_CID_GAIN, + type_: bindings::v4l2_ctrl_type_V4L2_CTRL_TYPE_INTEGER, + name: name.map(|b| b as i8), + minimum: Gain::MIN as i64, + maximum: Gain::MAX as i64, + step: 1, + default_value: Gain::DEFAULT as i64, + flags: 0, + elems: 1, + elem_size: std::mem::size_of::() as u32, + ..Default::default() + } + } + + fn user_class_query_ext_ctrl(&self) -> bindings::v4l2_query_ext_ctrl { + let name_str = "User Controls"; + let mut name = [0u8; 32]; + name[0..name_str.len()].copy_from_slice(name_str.as_bytes()); + bindings::v4l2_query_ext_ctrl { + id: bindings::V4L2_CID_USER_CLASS, + type_: bindings::v4l2_ctrl_type_V4L2_CTRL_TYPE_CTRL_CLASS, + name: name.map(|b| b as i8), + // V4L2 standard requires control class headers to be marked as both RO and WO. + flags: bindings::V4L2_CTRL_FLAG_READ_ONLY | bindings::V4L2_CTRL_FLAG_WRITE_ONLY, + ..Default::default() + } + } + + fn camera_class_query_ext_ctrl(&self) -> bindings::v4l2_query_ext_ctrl { + let name_str = "Camera Controls"; + let mut name = [0u8; 32]; + name[0..name_str.len()].copy_from_slice(name_str.as_bytes()); + bindings::v4l2_query_ext_ctrl { + id: bindings::V4L2_CID_CAMERA_CLASS, + type_: bindings::v4l2_ctrl_type_V4L2_CTRL_TYPE_CTRL_CLASS, + name: name.map(|b| b as i8), + // V4L2 standard requires control class headers to be marked as both RO and WO. + flags: bindings::V4L2_CTRL_FLAG_READ_ONLY | bindings::V4L2_CTRL_FLAG_WRITE_ONLY, + ..Default::default() + } + } } impl VirtioMediaDevice for EmulatedCamera @@ -724,7 +830,7 @@ where let buffer = host_buffer.v4l2_buffer.clone(); if session.streaming { - session.process_queued_buffers(&mut self.evt_queue)?; + session.process_queued_buffers(&mut self.evt_queue, &self.controls)?; } Ok(buffer) @@ -736,7 +842,7 @@ where } session.streaming = true; - session.process_queued_buffers(&mut self.evt_queue)?; + session.process_queued_buffers(&mut self.evt_queue, &self.controls)?; Ok(()) } @@ -839,13 +945,26 @@ where flags: QueryCtrlFlags, ) -> IoctlResult { let id: u32 = unsafe { std::mem::transmute(id) }; - // If V4L2_CTRL_FLAG_NEXT_CTRL present returns the first control with a higher ID. if flags.contains(QueryCtrlFlags::NEXT) { - if id < CID_LENS_FACING { + if id < bindings::V4L2_CID_USER_CLASS { + return Ok(self.user_class_query_ext_ctrl()); + } else if id < bindings::V4L2_CID_GAIN { + return Ok(self.gain_query_ext_ctrl()); + } else if id < bindings::V4L2_CID_CAMERA_CLASS { + return Ok(self.camera_class_query_ext_ctrl()); + } else if id < CID_LENS_FACING { + return Ok(self.lens_facing_query_ext_ctrl()); + } + } else { + if id == bindings::V4L2_CID_USER_CLASS { + return Ok(self.user_class_query_ext_ctrl()); + } else if id == bindings::V4L2_CID_GAIN { + return Ok(self.gain_query_ext_ctrl()); + } else if id == bindings::V4L2_CID_CAMERA_CLASS { + return Ok(self.camera_class_query_ext_ctrl()); + } else if id == CID_LENS_FACING { return Ok(self.lens_facing_query_ext_ctrl()); } - } else if id == CID_LENS_FACING { - return Ok(self.lens_facing_query_ext_ctrl()); } return Err(libc::EINVAL); } @@ -853,15 +972,51 @@ where fn g_ext_ctrls( &mut self, _session: &Self::Session, - _which: CtrlWhich, + which: CtrlWhich, ctrls: &mut bindings::v4l2_ext_controls, ctrl_array: &mut Vec, _user_regions: Vec>, ) -> IoctlResult<()> { - for ctrl in ctrl_array { + // Validate control class. Also handles class support queries when count == 0. + match which { + CtrlWhich::Current | CtrlWhich::Default => {} + CtrlWhich::Class(class) => { + if class != bindings::V4L2_CTRL_CLASS_USER && class != bindings::V4L2_CTRL_CLASS_CAMERA { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + _ => { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + + // Ensure all requested controls belong to the selected class. + if let CtrlWhich::Class(class_id) = which { + 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); + } + } + } + + // Process controls. Class controls are write-only headers and must fail on read. + 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; + return Err(libc::EACCES); + } + bindings::V4L2_CID_GAIN => { + ctrl.__bindgen_anon_1.value = match which { + CtrlWhich::Default => Gain::DEFAULT, + _ => self.controls.gain.value(), + }; + } CID_LENS_FACING => { - ctrl.__bindgen_anon_1.value = self.lens_facing as i32; + ctrl.__bindgen_anon_1.value = self.controls.lens_facing as i32; } _ => { ctrls.error_idx = ctrls.count; @@ -869,44 +1024,144 @@ where } } } + ctrls.error_idx = ctrls.count; Ok(()) } fn try_ext_ctrls( &mut self, _session: &Self::Session, - _which: CtrlWhich, + which: CtrlWhich, ctrls: &mut bindings::v4l2_ext_controls, ctrl_array: &mut Vec, _user_regions: Vec>, ) -> IoctlResult<()> { + // Validate control class. Setting defaults is not allowed for TRY/SET. + match which { + CtrlWhich::Current => {} + CtrlWhich::Class(class) => { + if class != bindings::V4L2_CTRL_CLASS_USER && class != bindings::V4L2_CTRL_CLASS_CAMERA { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + _ => { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + + // Ensure all requested controls belong to the selected class. + if let CtrlWhich::Class(class_id) = which { + for (idx, ctrl) in ctrl_array.iter().enumerate() { + if v4l2_ctrl_id2which(ctrl.id) != class_id { + ctrls.error_idx = idx as u32; + return Err(libc::EINVAL); + } + } + } + + // Validate control values. Class controls are read-only headers and must fail on write/try. for (idx, ctrl) in ctrl_array.iter_mut().enumerate() { - ctrls.error_idx = idx as u32; - let err_code = match ctrl.id { - CID_LENS_FACING => libc::EACCES, - _ => libc::EINVAL, - }; - return Err(err_code); + match ctrl.id { + bindings::V4L2_CID_USER_CLASS | bindings::V4L2_CID_CAMERA_CLASS => { + ctrls.error_idx = idx as u32; + return Err(libc::EACCES); + } + bindings::V4L2_CID_GAIN => { + let value = unsafe { ctrl.__bindgen_anon_1.value }; + if let Err(err) = Gain::new(value) { + ctrls.error_idx = idx as u32; + return Err(err); + } + } + CID_LENS_FACING => { + ctrls.error_idx = idx as u32; + return Err(libc::EACCES); + } + _ => { + ctrls.error_idx = idx as u32; + return Err(libc::EINVAL); + } + } } + ctrls.error_idx = ctrls.count; Ok(()) } fn s_ext_ctrls( &mut self, - _session: &mut Self::Session, - _which: CtrlWhich, + session: &mut Self::Session, + which: CtrlWhich, ctrls: &mut bindings::v4l2_ext_controls, ctrl_array: &mut Vec, _user_regions: Vec>, ) -> IoctlResult<()> { - for ctrl in ctrl_array { - ctrls.error_idx = ctrls.count; - let err_code = match ctrl.id { - CID_LENS_FACING => libc::EACCES, - _ => libc::EINVAL, - }; - return Err(err_code); + // Validate control class. Setting defaults is not allowed for TRY/SET. + match which { + CtrlWhich::Current => {} + CtrlWhich::Class(class) => { + if class != bindings::V4L2_CTRL_CLASS_USER && class != bindings::V4L2_CTRL_CLASS_CAMERA { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + _ => { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } + + // Ensure all requested controls belong to the selected class. + if let CtrlWhich::Class(class_id) = which { + 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); + } + } + } + + // Apply control values. Class controls are read-only headers and must fail on write/try. + 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; + return Err(libc::EACCES); + } + bindings::V4L2_CID_GAIN => { + let value = unsafe { ctrl.__bindgen_anon_1.value }; + match Gain::new(value) { + Ok(gain) => { + if self.controls.gain != gain { + self.controls.gain = gain; + let ctrl_event = bindings::v4l2_event { + type_: bindings::V4L2_EVENT_CTRL, + id: bindings::V4L2_CID_GAIN, + ..Default::default() + }; + self.evt_queue.send_event(V4l2Event::Event(SessionEvent::new( + session.id, ctrl_event, + ))); + } + } + Err(err) => { + ctrls.error_idx = ctrls.count; + return Err(err); + } + } + } + CID_LENS_FACING => { + ctrls.error_idx = ctrls.count; + return Err(libc::EACCES); + } + _ => { + ctrls.error_idx = ctrls.count; + return Err(libc::EINVAL); + } + } } + ctrls.error_idx = ctrls.count; Ok(()) } @@ -921,16 +1176,20 @@ where } match event { V4l2EventType::Ctrl(id) => match id { - CID_LENS_FACING => { + CID_LENS_FACING | bindings::V4L2_CID_GAIN => { let ctrl_event = bindings::v4l2_event { type_: bindings::V4L2_EVENT_CTRL, - id: CID_LENS_FACING, + id, ..Default::default() }; self.evt_queue .send_event(V4l2Event::Event(SessionEvent::new(session.id, ctrl_event))); Ok(()) } + bindings::V4L2_CID_USER_CLASS | bindings::V4L2_CID_CAMERA_CLASS => { + // Subscription succeeds, but we do not send any initial event. + Ok(()) + } _ => Err(libc::EINVAL), }, _ => Err(libc::EINVAL), @@ -942,7 +1201,12 @@ where _session: &mut Self::Session, event: bindings::v4l2_event_subscription, ) -> IoctlResult<()> { - return if event.type_ == bindings::V4L2_EVENT_CTRL && event.id == CID_LENS_FACING { + return if event.type_ == bindings::V4L2_EVENT_CTRL + && (event.id == CID_LENS_FACING + || event.id == bindings::V4L2_CID_GAIN + || event.id == bindings::V4L2_CID_USER_CLASS + || event.id == bindings::V4L2_CID_CAMERA_CLASS) + { Ok(()) } else { Err(libc::EINVAL) From 95607e5c0c79b1dc5ec7e17556df1b58f2faa246 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Wed, 29 Jul 2026 14:18:04 -0700 Subject: [PATCH 12/13] Update compile_commands.json generator Upstream is unmaintained, this fork has continued development. Bug: b/540519007 Test: bazel run @hedron_compile_commands//:refresh_all --- .../hedron_compile_commands.MODULE.bazel | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/base/cvd/build_external/hedron_compile_commands/hedron_compile_commands.MODULE.bazel b/base/cvd/build_external/hedron_compile_commands/hedron_compile_commands.MODULE.bazel index 9bbd5435a3a..ca897581c4b 100644 --- a/base/cvd/build_external/hedron_compile_commands/hedron_compile_commands.MODULE.bazel +++ b/base/cvd/build_external/hedron_compile_commands/hedron_compile_commands.MODULE.bazel @@ -2,9 +2,8 @@ # https://github.com/hedronvision/bazel-compile-commands-extractor git_override( module_name = "hedron_compile_commands", - # While waiting for - # https://github.com/hedronvision/bazel-compile-commands-extractor/pull/219 - # to be merged. - commit = "f5fbd4cee671d8d908f37c83abaf70fba5928fc7", - remote = "https://github.com/mikael-s-persson/bazel-compile-commands-extractor", + # Upstream is unmaintained, see + # https://github.com/helly25/bazel-compile-commands-extractor/blob/1f9360db1834d115c48279d38a97f30d64d3fd4a/FORK.md + commit = "1f9360db1834d115c48279d38a97f30d64d3fd4a", + remote = "https://github.com/helly25/bazel-compile-commands-extractor.git", ) From b1c1c8c44a0864427c30b8b725352cb85eef194f Mon Sep 17 00:00:00 2001 From: 3405691582 Date: Thu, 30 Jul 2026 18:09:04 +0000 Subject: [PATCH 13/13] Update to v1.55.2. --- base/debian/changelog | 16 ++++++++++++++++ container/debian/changelog | 7 +++++++ .../debian/changelog | 6 ++++++ frontend/debian/changelog | 6 ++++++ 4 files changed, 35 insertions(+) diff --git a/base/debian/changelog b/base/debian/changelog index aad8b93badd..5932b449e9b 100644 --- a/base/debian/changelog +++ b/base/debian/changelog @@ -1,3 +1,19 @@ +cuttlefish-common (1.55.2) unstable; urgency=medium + + * Update compile_commands.json generator + * Emulate signal gain for emulated_camera_mplane. + * Fix dependency issues with fetch:fetch_cvd + * Fix build issues with fetch:fetch_context + * Fix dependency issues with fetch:downloaders + * Fix dependency issues with fetch:build_api_flags + * Fix dependency issues with fetch:build_api_credentials + * modem_simulator: avoid referring to a dead object + * modem_simulator: fix the possible OOB if the buffer is not null terminated + * modem_simulator: prevent unhandled exceptions for incorrect input + * modem_simulator: prevent unhandled exceptions for strings shorter than 2 + + -- 3405691582 Thu, 30 Jul 2026 18:04:13 +0000 + cuttlefish-common (1.55.1) unstable; urgency=medium * Ignore ancient builds with higher safe levels by @Databean in https://github.com/google/android-cuttlefish/pull/2776 diff --git a/container/debian/changelog b/container/debian/changelog index 72598edf35b..6883edf8085 100644 --- a/container/debian/changelog +++ b/container/debian/changelog @@ -1,3 +1,10 @@ +cuttlefish-container (1.55.2) unstable; urgency=medium + + * Update to v1.55.2. + * Reduce the number of nginx worker processes in container + + -- 3405691582 Thu, 30 Jul 2026 18:04:05 +0000 + cuttlefish-container (1.55.1) unstable; urgency=medium * N/A diff --git a/cuttlefish-integration-gigabyte-arm64/debian/changelog b/cuttlefish-integration-gigabyte-arm64/debian/changelog index ae1f0607b46..a090f0791a3 100644 --- a/cuttlefish-integration-gigabyte-arm64/debian/changelog +++ b/cuttlefish-integration-gigabyte-arm64/debian/changelog @@ -1,3 +1,9 @@ +cuttlefish-integration-gigabyte-arm64 (1.55.2) unstable; urgency=medium + + * N/A + + -- 3405691582 Thu, 30 Jul 2026 18:03:34 +0000 + cuttlefish-integration-gigabyte-arm64 (1.55.1) unstable; urgency=medium * Update relevant values in e2e tests by @ser-io in https://github.com/google/android-cuttlefish/pull/2698 diff --git a/frontend/debian/changelog b/frontend/debian/changelog index f0656f02a5c..7b6bc6e8180 100644 --- a/frontend/debian/changelog +++ b/frontend/debian/changelog @@ -1,3 +1,9 @@ +cuttlefish-frontend (1.55.2) unstable; urgency=medium + + * N/A + + -- 3405691582 Thu, 30 Jul 2026 18:03:56 +0000 + cuttlefish-frontend (1.55.1) unstable; urgency=medium * Route per-instance start API by @SuperStrongDinosaur in https://github.com/google/android-cuttlefish/pull/2618