xref: /aosp_15_r20/external/crosvm/power_monitor/src/powerd/client.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Dbus client for sending request to powerd to get power properties.
6 
7 use std::error::Error;
8 use std::time::Duration;
9 
10 use dbus::blocking::Connection;
11 use protobuf::Message;
12 use remain::sorted;
13 use system_api::client::OrgChromiumPowerManager;
14 use thiserror::Error;
15 
16 use crate::powerd::POWER_INTERFACE_NAME;
17 use crate::powerd::POWER_OBJECT_PATH;
18 use crate::protos::power_supply_properties::PowerSupplyProperties;
19 use crate::PowerClient;
20 use crate::PowerData;
21 
22 // 25 seconds is the default timeout for dbus-send.
23 const DEFAULT_DBUS_TIMEOUT: Duration = Duration::from_secs(25);
24 
25 pub struct DBusClient {
26     connection: Connection,
27 }
28 
29 #[sorted]
30 #[derive(Error, Debug)]
31 pub enum DBusClientError {
32     #[error("failed to convert protobuf message: {0}")]
33     ConvertProtobuf(protobuf::Error),
34     #[error("failed to connect to D-Bus: {0}")]
35     DBusConnect(dbus::Error),
36     #[error("failed to read D-Bus message: {0}")]
37     DBusRead(dbus::Error),
38 }
39 
40 impl DBusClient {
41     /// Creates a new blocking dbus connection to system bus.
connect() -> std::result::Result<Box<dyn PowerClient>, Box<dyn Error>>42     pub fn connect() -> std::result::Result<Box<dyn PowerClient>, Box<dyn Error>> {
43         let channel = dbus::channel::Channel::get_private(dbus::channel::BusType::System)
44             .map_err(DBusClientError::DBusConnect)?;
45 
46         let connection = dbus::blocking::Connection::from(channel);
47 
48         Ok(Box::new(Self { connection }))
49     }
50 }
51 
52 // Send GetPowerSupplyProperties dbus request to power_manager(powerd), blocks until it gets
53 // response, and converts the response into PowerData.
54 impl PowerClient for DBusClient {
get_power_data(&mut self) -> std::result::Result<PowerData, Box<dyn Error>>55     fn get_power_data(&mut self) -> std::result::Result<PowerData, Box<dyn Error>> {
56         let proxy = self.connection.with_proxy(
57             POWER_INTERFACE_NAME,
58             POWER_OBJECT_PATH,
59             DEFAULT_DBUS_TIMEOUT,
60         );
61         let data_bytes = proxy
62             .get_power_supply_properties()
63             .map_err(DBusClientError::DBusRead)?;
64         let mut props = PowerSupplyProperties::new();
65         props
66             .merge_from_bytes(&data_bytes)
67             .map_err(DBusClientError::ConvertProtobuf)?;
68         let data: PowerData = props.into();
69         Ok(data)
70     }
71 }
72