power_monitor/powerd/
client.rs

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
7use std::error::Error;
8use std::time::Duration;
9use std::time::SystemTime;
10
11use dbus::blocking::Connection;
12use protobuf::Message;
13use remain::sorted;
14use system_api::client::OrgChromiumPowerManager;
15use thiserror::Error;
16
17use crate::powerd::POWER_INTERFACE_NAME;
18use crate::powerd::POWER_OBJECT_PATH;
19use crate::protos::power_supply_properties::PowerSupplyProperties;
20use crate::PowerClient;
21use crate::PowerData;
22
23// 25 seconds is the default timeout for dbus-send.
24const DEFAULT_DBUS_TIMEOUT: Duration = Duration::from_secs(25);
25
26pub struct DBusClient {
27    last_request_timestamp: Option<SystemTime>,
28    connection: Connection,
29}
30
31#[sorted]
32#[derive(Error, Debug)]
33pub enum DBusClientError {
34    #[error("failed to convert protobuf message: {0}")]
35    ConvertProtobuf(protobuf::Error),
36    #[error("failed to connect to D-Bus: {0}")]
37    DBusConnect(dbus::Error),
38    #[error("failed to read D-Bus message: {0}")]
39    DBusRead(dbus::Error),
40}
41
42impl DBusClient {
43    /// Creates a new blocking dbus connection to system bus.
44    pub fn connect() -> std::result::Result<Box<dyn PowerClient>, Box<dyn Error>> {
45        let channel = dbus::channel::Channel::get_private(dbus::channel::BusType::System)
46            .map_err(DBusClientError::DBusConnect)?;
47
48        let connection = dbus::blocking::Connection::from(channel);
49
50        Ok(Box::new(Self {
51            connection,
52            last_request_timestamp: None,
53        }))
54    }
55}
56
57// Send GetPowerSupplyProperties dbus request to power_manager(powerd), blocks until it gets
58// response, and converts the response into PowerData.
59impl PowerClient for DBusClient {
60    fn last_request_timestamp(&self) -> Option<SystemTime> {
61        self.last_request_timestamp
62    }
63
64    fn get_power_data(&mut self) -> std::result::Result<PowerData, Box<dyn Error>> {
65        self.last_request_timestamp = Some(SystemTime::now());
66
67        let proxy = self.connection.with_proxy(
68            POWER_INTERFACE_NAME,
69            POWER_OBJECT_PATH,
70            DEFAULT_DBUS_TIMEOUT,
71        );
72        let data_bytes = proxy
73            .get_power_supply_properties()
74            .map_err(DBusClientError::DBusRead)?;
75        let mut props = PowerSupplyProperties::new();
76        props
77            .merge_from_bytes(&data_bytes)
78            .map_err(DBusClientError::ConvertProtobuf)?;
79        let data: PowerData = props.into();
80        Ok(data)
81    }
82}