| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use std::sync::Arc; |
| use std::sync::Mutex; |
| use std::time::Duration; |
| |
| use dbus::blocking::Connection; |
| use log::error; |
| use log::info; |
| |
| use crate::command_runner::CommandRunner; |
| use crate::context::Context; |
| use crate::error::HwsecError; |
| |
| /// Define the name used on powerd dbus. |
| const POWERD_DBUS_NAME: &str = "org.chromium.PowerManager"; |
| /// Define the path used within powerd dbus. |
| const POWERD_DBUS_PATH: &str = "/org/chromium/PowerManager"; |
| const TIMEOUT_DURATION: Duration = Duration::from_secs(60); |
| #[derive(Debug)] |
| struct SuspendImminent {} |
| |
| impl dbus::arg::ReadAll for SuspendImminent { |
| fn read(_i: &mut dbus::arg::Iter) -> std::result::Result<Self, dbus::arg::TypeMismatchError> { |
| Ok(SuspendImminent {}) |
| } |
| } |
| |
| impl dbus::message::SignalArgs for SuspendImminent { |
| const NAME: &'static str = "SuspendImminent"; |
| const INTERFACE: &'static str = POWERD_DBUS_NAME; |
| } |
| |
| fn send_disable_deep_sleep_command_to_cr50(ctx: &mut impl Context) -> Result<(), HwsecError> { |
| info!("Sending disable deep sleep command to Cr50"); |
| let trunks_send_result = ctx |
| .cmd_runner() |
| .run("trunks_send", vec!["--raw", "80010000000c20000000003b"]) |
| .map_err(|_| { |
| eprintln!("ERROR: Failed to run gsctool."); |
| HwsecError::CommandRunnerError |
| })?; |
| |
| if trunks_send_result.status.success() { |
| info!("Disable sleep command sent to Cr50"); |
| Ok(()) |
| } else { |
| error!("Error sending disable sleep command to Cr50"); |
| Err(HwsecError::InternalError) |
| } |
| } |
| |
| pub fn monitor_suspend_dbus_signal(ctx: &mut impl Context) -> Result<(), HwsecError> { |
| // Start up a connection to the system bus. |
| let conn = Connection::new_system().map_err(|_| { |
| error!("Failed to start system dbus connection"); |
| HwsecError::InternalError |
| })?; |
| |
| let proxy = conn.with_proxy(POWERD_DBUS_NAME, POWERD_DBUS_PATH, TIMEOUT_DURATION); |
| |
| let signal = Arc::new(Mutex::new(false)); |
| let signal_copy = Arc::clone(&signal); |
| // Listen to the SuspendImminent signal on the org.chromium.PowerManager interface. |
| info!("Start monitoring dbus for SuspendImminent signal"); |
| proxy |
| .match_signal( |
| move |_signal: SuspendImminent, _: &Connection, _: &dbus::Message| { |
| let mut received = signal_copy.lock().unwrap(); |
| *received = true; |
| // Return true to not abandon the match. |
| true |
| }, |
| ) |
| .map_err(|_| HwsecError::InternalError)?; |
| |
| // Listen to incoming signals forever. |
| loop { |
| conn.process(TIMEOUT_DURATION) |
| .map_err(|_| HwsecError::InternalError)?; |
| let mut received = signal.lock().unwrap(); |
| if *received { |
| info!("SuspendImminent signal received"); |
| send_disable_deep_sleep_command_to_cr50(ctx)?; |
| *received = false; |
| } |
| } |
| } |