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", ) diff --git a/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel b/base/cvd/cuttlefish/host/commands/cvd/fetch/BUILD.bazel index 5db93be1685..97e7db26f57 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", ], ) @@ -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", ], ) @@ -127,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", @@ -173,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", @@ -187,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", @@ -214,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", @@ -226,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", 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" 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 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" 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)); 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; } } } 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, 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); 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) 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 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