power_monitor: add powerd client

This Cl adds powerd client in powerd module. The power client is a
blocking client that serves to send dbus request to powerd and receive
response. Currently, only GetPowerSupplyProperties dbus request is
supported. The GetPowerSupplyProperties will be used in following CLs.

BUG=b:361281568
TEST=cargo build --features=power-monitor-powerd

Change-Id: I5e9714bdd10ac3d5906995dfa35c34dd360f4567
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5915194
Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Yuan Yao <yuanyaogoog@chromium.org>
This commit is contained in:
Yuan Yao 2024-10-10 08:52:46 +00:00 committed by crosvm LUCI
parent 0090567d24
commit d8fbb091cb
5 changed files with 80 additions and 0 deletions

1
Cargo.lock generated
View file

@ -2259,6 +2259,7 @@ dependencies = [
"proto_build_tools",
"protobuf",
"remain",
"system_api",
"thiserror",
]

View file

@ -12,6 +12,7 @@ base = { path = "../base" }
dbus = { version = "0.9", optional = true }
protobuf = "3.2"
remain = "0.2"
system_api = { path = "../system_api"}
thiserror = "1.0.20"
[build-dependencies]

View file

@ -12,6 +12,10 @@ pub trait PowerMonitor: ReadNotifier {
fn read_message(&mut self) -> std::result::Result<Option<PowerData>, Box<dyn Error>>;
}
pub trait PowerClient {
fn get_power_data(&mut self) -> std::result::Result<PowerData, Box<dyn Error>>;
}
pub struct PowerData {
pub ac_online: bool,
pub battery: Option<BatteryData>,

View file

@ -14,7 +14,10 @@ use crate::PowerData;
// Interface name from power_manager/dbus_bindings/org.chromium.PowerManager.xml.
pub const POWER_INTERFACE_NAME: &str = "org.chromium.PowerManager";
// Object path from power_manager/dbus_bindings/org.chromium.PowerManager.xml.
pub const POWER_OBJECT_PATH: &str = "/org/chromium/PowerManager";
pub mod client;
pub mod monitor;
impl From<PowerSupplyProperties> for PowerData {

View file

@ -0,0 +1,71 @@
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Dbus client for sending request to powerd to get power properties.
use std::error::Error;
use std::time::Duration;
use dbus::blocking::Connection;
use protobuf::Message;
use remain::sorted;
use system_api::client::OrgChromiumPowerManager;
use thiserror::Error;
use crate::powerd::POWER_INTERFACE_NAME;
use crate::powerd::POWER_OBJECT_PATH;
use crate::protos::power_supply_properties::PowerSupplyProperties;
use crate::PowerClient;
use crate::PowerData;
// 25 seconds is the default timeout for dbus-send.
const DEFAULT_DBUS_TIMEOUT: Duration = Duration::from_secs(25);
pub struct DBusClient {
connection: Connection,
}
#[sorted]
#[derive(Error, Debug)]
pub enum DBusClientError {
#[error("failed to convert protobuf message: {0}")]
ConvertProtobuf(protobuf::Error),
#[error("failed to connect to D-Bus: {0}")]
DBusConnect(dbus::Error),
#[error("failed to read D-Bus message: {0}")]
DBusRead(dbus::Error),
}
impl DBusClient {
/// Creates a new blocking dbus connection to system bus.
pub fn connect() -> std::result::Result<Box<dyn PowerClient>, Box<dyn Error>> {
let channel = dbus::channel::Channel::get_private(dbus::channel::BusType::System)
.map_err(DBusClientError::DBusConnect)?;
let connection = dbus::blocking::Connection::from(channel);
Ok(Box::new(Self { connection }))
}
}
// Send GetPowerSupplyProperties dbus request to power_manager(powerd), blocks until it gets
// response, and converts the response into PowerData.
impl PowerClient for DBusClient {
fn get_power_data(&mut self) -> std::result::Result<PowerData, Box<dyn Error>> {
let proxy = self.connection.with_proxy(
POWER_INTERFACE_NAME,
POWER_OBJECT_PATH,
DEFAULT_DBUS_TIMEOUT,
);
let data_bytes = proxy
.get_power_supply_properties()
.map_err(DBusClientError::DBusRead)?;
let mut props = PowerSupplyProperties::new();
props
.merge_from_bytes(&data_bytes)
.map_err(DBusClientError::ConvertProtobuf)?;
let data: PowerData = props.into();
Ok(data)
}
}