mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-15 18:56:49 -04:00
manager/user: Add interface for remote relay interfaces
This commit is contained in:
parent
29ffb42a4e
commit
19d7e3e7c4
5 changed files with 465 additions and 18 deletions
|
@ -298,6 +298,27 @@
|
||||||
|
|
||||||
</interface>
|
</interface>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
com.steampowered.SteamOSManager1.RemoteInterface1
|
||||||
|
@short_description: TKTK
|
||||||
|
-->
|
||||||
|
<interface name="com.steampowered.SteamOSManager1.RemoteInterface1">
|
||||||
|
|
||||||
|
<method name="RegisterInterface">
|
||||||
|
<arg type="s" name="interface" direction="in"/>
|
||||||
|
<arg type="o" name="object" direction="in"/>
|
||||||
|
<arg type="b" name="registered" direction="out"/>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="UnregisterInterface">
|
||||||
|
<arg type="s" name="interface" direction="in"/>
|
||||||
|
<arg type="b" name="unregistered" direction="out"/>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<property name="RemoteInterfaces" type="as" access="read"/>
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
com.steampowered.SteamOSManager1.ScreenReader1
|
com.steampowered.SteamOSManager1.ScreenReader1
|
||||||
@short_description: Optional interface for managing a screen reader.
|
@short_description: Optional interface for managing a screen reader.
|
||||||
|
|
|
@ -25,6 +25,7 @@ mod hdmi_cec1;
|
||||||
mod low_power_mode1;
|
mod low_power_mode1;
|
||||||
mod manager2;
|
mod manager2;
|
||||||
mod performance_profile1;
|
mod performance_profile1;
|
||||||
|
mod remote_interface1;
|
||||||
mod screenreader0;
|
mod screenreader0;
|
||||||
mod storage1;
|
mod storage1;
|
||||||
mod tdp_limit1;
|
mod tdp_limit1;
|
||||||
|
@ -44,6 +45,7 @@ pub use crate::hdmi_cec1::HdmiCec1Proxy;
|
||||||
pub use crate::low_power_mode1::LowPowerMode1Proxy;
|
pub use crate::low_power_mode1::LowPowerMode1Proxy;
|
||||||
pub use crate::manager2::Manager2Proxy;
|
pub use crate::manager2::Manager2Proxy;
|
||||||
pub use crate::performance_profile1::PerformanceProfile1Proxy;
|
pub use crate::performance_profile1::PerformanceProfile1Proxy;
|
||||||
|
pub use crate::remote_interface1::RemoteInterface1Proxy;
|
||||||
pub use crate::screenreader0::ScreenReader0Proxy;
|
pub use crate::screenreader0::ScreenReader0Proxy;
|
||||||
pub use crate::storage1::Storage1Proxy;
|
pub use crate::storage1::Storage1Proxy;
|
||||||
pub use crate::tdp_limit1::TdpLimit1Proxy;
|
pub use crate::tdp_limit1::TdpLimit1Proxy;
|
||||||
|
|
35
steamos-manager-proxy/src/remote_interface1.rs
Normal file
35
steamos-manager-proxy/src/remote_interface1.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
//! # D-Bus interface proxy for: `com.steampowered.SteamOSManager1.RemoteInterface1`
|
||||||
|
//!
|
||||||
|
//! This code was generated by `zbus-xmlgen` `5.1.0` from D-Bus introspection data.
|
||||||
|
//! Source: `com.steampowered.SteamOSManager1.xml`.
|
||||||
|
//!
|
||||||
|
//! You may prefer to adapt it, instead of using it verbatim.
|
||||||
|
//!
|
||||||
|
//! More information can be found in the [Writing a client proxy] section of the zbus
|
||||||
|
//! documentation.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html
|
||||||
|
//! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces,
|
||||||
|
use zbus::proxy;
|
||||||
|
#[proxy(
|
||||||
|
interface = "com.steampowered.SteamOSManager1.RemoteInterface1",
|
||||||
|
default_service = "com.steampowered.SteamOSManager1",
|
||||||
|
default_path = "/com/steampowered/SteamOSManager1",
|
||||||
|
assume_defaults = true
|
||||||
|
)]
|
||||||
|
pub trait RemoteInterface1 {
|
||||||
|
/// RegisterInterface method
|
||||||
|
fn register_interface(
|
||||||
|
&self,
|
||||||
|
interface: &str,
|
||||||
|
object: &zbus::zvariant::ObjectPath<'_>,
|
||||||
|
) -> zbus::Result<bool>;
|
||||||
|
|
||||||
|
/// UnregisterInterface method
|
||||||
|
fn unregister_interface(&self, interface: &str) -> zbus::Result<bool>;
|
||||||
|
|
||||||
|
/// RemoteInterfaces property
|
||||||
|
#[zbus(property)]
|
||||||
|
fn remote_interfaces(&self) -> zbus::Result<Vec<String>>;
|
||||||
|
}
|
|
@ -11,12 +11,18 @@ use std::collections::HashMap;
|
||||||
use tokio::fs::try_exists;
|
use tokio::fs::try_exists;
|
||||||
use tokio::sync::mpsc::{Sender, UnboundedSender};
|
use tokio::sync::mpsc::{Sender, UnboundedSender};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
use tokio::task::{spawn, JoinHandle};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use zbus::object_server::{Interface, SignalEmitter};
|
use zbus::fdo::{self, DBusProxy};
|
||||||
|
use zbus::message::Header;
|
||||||
|
use zbus::names::{BusName, UniqueName};
|
||||||
|
use zbus::object_server::{Interface, InterfaceRef, SignalEmitter};
|
||||||
use zbus::proxy::{Builder, CacheProperties};
|
use zbus::proxy::{Builder, CacheProperties};
|
||||||
use zbus::zvariant::Fd;
|
use zbus::zvariant::{Fd, ObjectPath};
|
||||||
use zbus::{fdo, interface, zvariant, Connection, ObjectServer, Proxy};
|
use zbus::{interface, zvariant, Connection, ObjectServer, Proxy};
|
||||||
|
|
||||||
|
use steamos_manager_macros::remote;
|
||||||
|
|
||||||
use crate::cec::{HdmiCecControl, HdmiCecState};
|
use crate::cec::{HdmiCecControl, HdmiCecState};
|
||||||
use crate::daemon::user::Command;
|
use crate::daemon::user::Command;
|
||||||
|
@ -34,6 +40,11 @@ use crate::power::{
|
||||||
get_gpu_clocks, get_gpu_clocks_range, get_gpu_performance_level, get_gpu_power_profile,
|
get_gpu_clocks, get_gpu_clocks_range, get_gpu_performance_level, get_gpu_power_profile,
|
||||||
get_max_charge_level, get_platform_profile, TdpManagerCommand,
|
get_max_charge_level, get_platform_profile, TdpManagerCommand,
|
||||||
};
|
};
|
||||||
|
use crate::proxy::{
|
||||||
|
BatteryChargeLimit1Proxy, FactoryReset1Proxy, FanControl1Proxy, GpuPerformanceLevel1Proxy,
|
||||||
|
GpuPowerProfile1Proxy, PerformanceProfile1Proxy, Storage1Proxy, UpdateBios1Proxy,
|
||||||
|
UpdateDock1Proxy,
|
||||||
|
};
|
||||||
use crate::screenreader::{OrcaManager, ScreenReaderAction, ScreenReaderMode};
|
use crate::screenreader::{OrcaManager, ScreenReaderAction, ScreenReaderMode};
|
||||||
use crate::wifi::{
|
use crate::wifi::{
|
||||||
get_wifi_backend, get_wifi_power_management_state, list_wifi_interfaces, WifiBackend,
|
get_wifi_backend, get_wifi_power_management_state, list_wifi_interfaces, WifiBackend,
|
||||||
|
@ -102,6 +113,88 @@ macro_rules! setter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! register_interface {
|
||||||
|
(($self:expr, $name:expr, $object:expr, $bus_name:expr, $connection:expr, $ctxt:expr); $($var:ident: $iface:ident,)*) => {
|
||||||
|
let object_server = $connection.object_server();
|
||||||
|
let object = $object.to_owned();
|
||||||
|
|
||||||
|
match $name {
|
||||||
|
$(_ if $name == <$iface as Interface>::name().as_str() => {
|
||||||
|
if $self.$var.is_some() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
if object_server
|
||||||
|
.interface::<_, $iface>(MANAGER_PATH)
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
if object_server
|
||||||
|
.interface::<_, <$iface as RemoteInterface>::Remote>(MANAGER_PATH)
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let remote = <$iface as RemoteInterface>::Remote::new(
|
||||||
|
&$bus_name.to_owned(),
|
||||||
|
object,
|
||||||
|
$connection,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
object_server.at(MANAGER_PATH, remote).await?;
|
||||||
|
let iface = object_server.interface
|
||||||
|
::<_, <$iface as RemoteInterface>::Remote>(MANAGER_PATH).await?;
|
||||||
|
if let Some(interlock) = iface.get_mut().await.interlock.take() {
|
||||||
|
let _ = interlock.send(());
|
||||||
|
}
|
||||||
|
$self.$var = Some(iface);
|
||||||
|
$self.remote_interfaces_changed(&$ctxt).await?;
|
||||||
|
Ok(true)
|
||||||
|
})*
|
||||||
|
_ => {
|
||||||
|
Err(fdo::Error::InvalidArgs(format!(
|
||||||
|
"Unknown interface {}", $name
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! unregister_interface {
|
||||||
|
(($self:expr, $name:expr, $sender:expr, $connection:expr, $ctxt:expr); $($var:ident: $iface:ident,)*) => {
|
||||||
|
let object_server = $connection.object_server();
|
||||||
|
|
||||||
|
match $name {
|
||||||
|
$(_ if $name == <$iface as Interface>::name().as_str() => {
|
||||||
|
let Some(iface) = $self.$var.as_ref() else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
if let Some(sender) = $sender {
|
||||||
|
let iface = iface.get().await;
|
||||||
|
let remote = iface.remote();
|
||||||
|
if remote != sender {
|
||||||
|
return Err(fdo::Error::AccessDenied(format!(
|
||||||
|
"Interface {} is owned by a different remote", $name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object_server.remove::<$iface, _>(MANAGER_PATH).await?;
|
||||||
|
$self.$var = None;
|
||||||
|
$self.remote_interfaces_changed($ctxt).await?;
|
||||||
|
Ok(true)
|
||||||
|
})*
|
||||||
|
_ => {
|
||||||
|
Err(fdo::Error::InvalidArgs(format!(
|
||||||
|
"Unknown interface {}", $name
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
trait RemoteInterface {
|
trait RemoteInterface {
|
||||||
type Remote: Interface;
|
type Remote: Interface;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +254,19 @@ struct PerformanceProfile1 {
|
||||||
tdp_limit_manager: Option<UnboundedSender<TdpManagerCommand>>,
|
tdp_limit_manager: Option<UnboundedSender<TdpManagerCommand>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct RemoteInterface1 {
|
||||||
|
remote_battery_charge_limit1: Option<InterfaceRef<BatteryChargeLimit1Remote>>,
|
||||||
|
remote_factory_reset1: Option<InterfaceRef<FactoryReset1Remote>>,
|
||||||
|
remote_fan_control1: Option<InterfaceRef<FanControl1Remote>>,
|
||||||
|
remote_gpu_performance_level1: Option<InterfaceRef<GpuPerformanceLevel1Remote>>,
|
||||||
|
remote_gpu_power_profile1: Option<InterfaceRef<GpuPowerProfile1Remote>>,
|
||||||
|
remote_performance_profile1: Option<InterfaceRef<PerformanceProfile1Remote>>,
|
||||||
|
remote_storage1: Option<InterfaceRef<Storage1Remote>>,
|
||||||
|
remote_update_bios1: Option<InterfaceRef<UpdateBios1Remote>>,
|
||||||
|
remote_update_dock1: Option<InterfaceRef<UpdateDock1Remote>>,
|
||||||
|
}
|
||||||
|
|
||||||
struct ScreenReader0 {
|
struct ScreenReader0 {
|
||||||
screen_reader: OrcaManager<'static>,
|
screen_reader: OrcaManager<'static>,
|
||||||
}
|
}
|
||||||
|
@ -274,7 +380,7 @@ impl BatteryChargeLimit1 {
|
||||||
const DEFAULT_SUGGESTED_MINIMUM_LIMIT: i32 = 10;
|
const DEFAULT_SUGGESTED_MINIMUM_LIMIT: i32 = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.BatteryChargeLimit1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.BatteryChargeLimit1")]
|
||||||
impl BatteryChargeLimit1 {
|
impl BatteryChargeLimit1 {
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
async fn max_charge_level(&self) -> fdo::Result<i32> {
|
async fn max_charge_level(&self) -> fdo::Result<i32> {
|
||||||
|
@ -326,7 +432,7 @@ impl CpuScaling1 {
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
async fn set_cpu_scaling_governor(
|
async fn set_cpu_scaling_governor(
|
||||||
&self,
|
&self,
|
||||||
governor: String,
|
governor: &str,
|
||||||
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
#[zbus(signal_emitter)] ctx: SignalEmitter<'_>,
|
||||||
) -> zbus::Result<()> {
|
) -> zbus::Result<()> {
|
||||||
let _: () = self
|
let _: () = self
|
||||||
|
@ -337,14 +443,14 @@ impl CpuScaling1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.FactoryReset1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.FactoryReset1")]
|
||||||
impl FactoryReset1 {
|
impl FactoryReset1 {
|
||||||
async fn prepare_factory_reset(&self, flags: u32) -> fdo::Result<u32> {
|
async fn prepare_factory_reset(&self, flags: u32) -> fdo::Result<u32> {
|
||||||
method!(self, "PrepareFactoryReset", flags)
|
method!(self, "PrepareFactoryReset", flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.FanControl1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.FanControl1")]
|
||||||
impl FanControl1 {
|
impl FanControl1 {
|
||||||
#[zbus(property)]
|
#[zbus(property)]
|
||||||
async fn fan_control_state(&self) -> fdo::Result<u32> {
|
async fn fan_control_state(&self) -> fdo::Result<u32> {
|
||||||
|
@ -362,7 +468,7 @@ impl FanControl1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPerformanceLevel1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.GpuPerformanceLevel1")]
|
||||||
impl GpuPerformanceLevel1 {
|
impl GpuPerformanceLevel1 {
|
||||||
#[zbus(property(emits_changed_signal = "const"))]
|
#[zbus(property(emits_changed_signal = "const"))]
|
||||||
async fn available_gpu_performance_levels(&self) -> fdo::Result<Vec<String>> {
|
async fn available_gpu_performance_levels(&self) -> fdo::Result<Vec<String>> {
|
||||||
|
@ -429,7 +535,7 @@ impl GpuPerformanceLevel1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.GpuPowerProfile1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.GpuPowerProfile1")]
|
||||||
impl GpuPowerProfile1 {
|
impl GpuPowerProfile1 {
|
||||||
#[zbus(property(emits_changed_signal = "const"))]
|
#[zbus(property(emits_changed_signal = "const"))]
|
||||||
async fn available_gpu_power_profiles(&self) -> fdo::Result<Vec<String>> {
|
async fn available_gpu_power_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||||
|
@ -551,7 +657,7 @@ impl Manager2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.PerformanceProfile1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.PerformanceProfile1")]
|
||||||
impl PerformanceProfile1 {
|
impl PerformanceProfile1 {
|
||||||
#[zbus(property(emits_changed_signal = "const"))]
|
#[zbus(property(emits_changed_signal = "const"))]
|
||||||
async fn available_performance_profiles(&self) -> fdo::Result<Vec<String>> {
|
async fn available_performance_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||||
|
@ -594,7 +700,7 @@ impl PerformanceProfile1 {
|
||||||
if let Some(manager) = self.tdp_limit_manager.as_ref() {
|
if let Some(manager) = self.tdp_limit_manager.as_ref() {
|
||||||
let manager = manager.clone();
|
let manager = manager.clone();
|
||||||
let _ = manager.send(TdpManagerCommand::UpdateDownloadMode);
|
let _ = manager.send(TdpManagerCommand::UpdateDownloadMode);
|
||||||
tokio::spawn(async move {
|
spawn(async move {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
manager.send(TdpManagerCommand::IsActive(tx))?;
|
manager.send(TdpManagerCommand::IsActive(tx))?;
|
||||||
if rx.await?? {
|
if rx.await?? {
|
||||||
|
@ -628,6 +734,122 @@ impl PerformanceProfile1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[interface(name = "com.steampowered.SteamOSManager1.RemoteInterface1")]
|
||||||
|
impl RemoteInterface1 {
|
||||||
|
async fn register_interface(
|
||||||
|
&mut self,
|
||||||
|
iface: &str,
|
||||||
|
object: ObjectPath<'_>,
|
||||||
|
#[zbus(header)] header: Header<'_>,
|
||||||
|
#[zbus(connection)] connection: &Connection,
|
||||||
|
#[zbus(signal_emitter)] ctxt: SignalEmitter<'_>,
|
||||||
|
) -> fdo::Result<bool> {
|
||||||
|
let Some(sender) = header.sender() else {
|
||||||
|
return Err(fdo::Error::InvalidArgs(String::from("Sender missing")));
|
||||||
|
};
|
||||||
|
let bus_name = BusName::Unique(sender.to_owned());
|
||||||
|
|
||||||
|
self.register_interface_impl(iface, object, &bus_name, connection, &ctxt)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unregister_interface(
|
||||||
|
&mut self,
|
||||||
|
iface: &str,
|
||||||
|
#[zbus(header)] header: Header<'_>,
|
||||||
|
#[zbus(connection)] connection: &Connection,
|
||||||
|
#[zbus(signal_emitter)] ctxt: SignalEmitter<'_>,
|
||||||
|
) -> fdo::Result<bool> {
|
||||||
|
let sender = header.sender();
|
||||||
|
if sender.is_none() {
|
||||||
|
return Err(fdo::Error::InvalidArgs(String::from("Sender missing")));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.unregister_interface_impl(iface, sender, connection, &ctxt)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[zbus(property)]
|
||||||
|
async fn remote_interfaces(&self) -> Vec<String> {
|
||||||
|
let mut ifaces = Vec::new();
|
||||||
|
if self.remote_battery_charge_limit1.is_some() {
|
||||||
|
ifaces.push(BatteryChargeLimit1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_factory_reset1.is_some() {
|
||||||
|
ifaces.push(FactoryReset1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_fan_control1.is_some() {
|
||||||
|
ifaces.push(FanControl1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_gpu_performance_level1.is_some() {
|
||||||
|
ifaces.push(GpuPerformanceLevel1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_gpu_power_profile1.is_some() {
|
||||||
|
ifaces.push(GpuPowerProfile1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_performance_profile1.is_some() {
|
||||||
|
ifaces.push(PerformanceProfile1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_storage1.is_some() {
|
||||||
|
ifaces.push(Storage1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_update_bios1.is_some() {
|
||||||
|
ifaces.push(UpdateBios1::name().to_string());
|
||||||
|
}
|
||||||
|
if self.remote_update_dock1.is_some() {
|
||||||
|
ifaces.push(UpdateDock1::name().to_string());
|
||||||
|
}
|
||||||
|
ifaces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemoteInterface1 {
|
||||||
|
async fn register_interface_impl(
|
||||||
|
&mut self,
|
||||||
|
iface: &str,
|
||||||
|
object: ObjectPath<'_>,
|
||||||
|
bus_name: &BusName<'_>,
|
||||||
|
connection: &Connection,
|
||||||
|
ctxt: &SignalEmitter<'_>,
|
||||||
|
) -> fdo::Result<bool> {
|
||||||
|
register_interface! {
|
||||||
|
(self, iface, object, bus_name, connection, ctxt);
|
||||||
|
|
||||||
|
remote_battery_charge_limit1: BatteryChargeLimit1,
|
||||||
|
remote_factory_reset1: FactoryReset1,
|
||||||
|
remote_fan_control1: FanControl1,
|
||||||
|
remote_gpu_performance_level1: GpuPerformanceLevel1,
|
||||||
|
remote_gpu_power_profile1: GpuPowerProfile1,
|
||||||
|
remote_performance_profile1: PerformanceProfile1,
|
||||||
|
remote_storage1: Storage1,
|
||||||
|
remote_update_bios1: UpdateBios1,
|
||||||
|
remote_update_dock1: UpdateDock1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unregister_interface_impl(
|
||||||
|
&mut self,
|
||||||
|
iface: &str,
|
||||||
|
sender: Option<&UniqueName<'_>>,
|
||||||
|
connection: &Connection,
|
||||||
|
ctxt: &SignalEmitter<'_>,
|
||||||
|
) -> fdo::Result<bool> {
|
||||||
|
unregister_interface! {
|
||||||
|
(self, iface, sender, connection, ctxt);
|
||||||
|
|
||||||
|
remote_battery_charge_limit1: BatteryChargeLimit1,
|
||||||
|
remote_factory_reset1: FactoryReset1,
|
||||||
|
remote_fan_control1: FanControl1,
|
||||||
|
remote_gpu_performance_level1: GpuPerformanceLevel1,
|
||||||
|
remote_gpu_power_profile1: GpuPowerProfile1,
|
||||||
|
remote_performance_profile1: PerformanceProfile1,
|
||||||
|
remote_storage1: Storage1,
|
||||||
|
remote_update_bios1: UpdateBios1,
|
||||||
|
remote_update_dock1: UpdateDock1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ScreenReader0 {
|
impl ScreenReader0 {
|
||||||
async fn new(connection: &Connection) -> Result<ScreenReader0> {
|
async fn new(connection: &Connection) -> Result<ScreenReader0> {
|
||||||
let screen_reader = OrcaManager::new(connection).await?;
|
let screen_reader = OrcaManager::new(connection).await?;
|
||||||
|
@ -751,7 +973,7 @@ impl ScreenReader0 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.Storage1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.Storage1")]
|
||||||
impl Storage1 {
|
impl Storage1 {
|
||||||
async fn format_device(
|
async fn format_device(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -824,14 +1046,14 @@ impl TdpLimit1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.UpdateBios1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.UpdateBios1")]
|
||||||
impl UpdateBios1 {
|
impl UpdateBios1 {
|
||||||
async fn update_bios(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
async fn update_bios(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
||||||
job_method!(self, "UpdateBios")
|
job_method!(self, "UpdateBios")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[interface(name = "com.steampowered.SteamOSManager1.UpdateDock1")]
|
#[remote(name = "com.steampowered.SteamOSManager1.UpdateDock1")]
|
||||||
impl UpdateDock1 {
|
impl UpdateDock1 {
|
||||||
async fn update_dock(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
async fn update_dock(&mut self) -> fdo::Result<zvariant::OwnedObjectPath> {
|
||||||
job_method!(self, "UpdateDock")
|
job_method!(self, "UpdateDock")
|
||||||
|
@ -1053,7 +1275,7 @@ async fn create_device_interfaces(
|
||||||
}
|
}
|
||||||
|
|
||||||
let object_server = object_server.clone();
|
let object_server = object_server.clone();
|
||||||
tokio::spawn(async move {
|
spawn(async move {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
manager.send(TdpManagerCommand::IsActive(tx))?;
|
manager.send(TdpManagerCommand::IsActive(tx))?;
|
||||||
if rx.await?? {
|
if rx.await?? {
|
||||||
|
@ -1114,6 +1336,7 @@ pub(crate) async fn create_interfaces(
|
||||||
proxy: proxy.clone(),
|
proxy: proxy.clone(),
|
||||||
channel: daemon,
|
channel: daemon,
|
||||||
};
|
};
|
||||||
|
let remote_interface = RemoteInterface1::default();
|
||||||
let screen_reader = ScreenReader0::new(&session).await?;
|
let screen_reader = ScreenReader0::new(&session).await?;
|
||||||
let wifi_power_management = WifiPowerManagement1 {
|
let wifi_power_management = WifiPowerManagement1 {
|
||||||
proxy: proxy.clone(),
|
proxy: proxy.clone(),
|
||||||
|
@ -1168,6 +1391,7 @@ pub(crate) async fn create_interfaces(
|
||||||
}
|
}
|
||||||
|
|
||||||
object_server.at(MANAGER_PATH, manager2).await?;
|
object_server.at(MANAGER_PATH, manager2).await?;
|
||||||
|
object_server.at(MANAGER_PATH, remote_interface).await?;
|
||||||
|
|
||||||
if try_exists(path("/usr/bin/orca")).await? {
|
if try_exists(path("/usr/bin/orca")).await? {
|
||||||
object_server.at(MANAGER_PATH, screen_reader).await?;
|
object_server.at(MANAGER_PATH, screen_reader).await?;
|
||||||
|
@ -1196,9 +1420,11 @@ mod test {
|
||||||
FormatDeviceConfig, PlatformConfig, ResetConfig, ScriptConfig, ServiceConfig, StorageConfig,
|
FormatDeviceConfig, PlatformConfig, ResetConfig, ScriptConfig, ServiceConfig, StorageConfig,
|
||||||
};
|
};
|
||||||
use crate::power::TdpLimitingMethod;
|
use crate::power::TdpLimitingMethod;
|
||||||
|
use crate::proxy::RemoteInterface1Proxy;
|
||||||
use crate::systemd::test::{MockManager, MockUnit};
|
use crate::systemd::test::{MockManager, MockUnit};
|
||||||
use crate::{path, power, testing};
|
use crate::{path, power, testing};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, ensure};
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -1207,10 +1433,9 @@ mod test {
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use zbus::object_server::Interface;
|
use zbus::object_server::Interface;
|
||||||
use zbus::Connection;
|
|
||||||
|
|
||||||
struct TestHandle {
|
struct TestHandle {
|
||||||
_handle: testing::TestHandle,
|
handle: testing::TestHandle,
|
||||||
connection: Connection,
|
connection: Connection,
|
||||||
_rx_job: UnboundedReceiver<JobManagerCommand>,
|
_rx_job: UnboundedReceiver<JobManagerCommand>,
|
||||||
rx_tdp: Option<UnboundedReceiver<TdpManagerCommand>>,
|
rx_tdp: Option<UnboundedReceiver<TdpManagerCommand>>,
|
||||||
|
@ -1328,7 +1553,7 @@ mod test {
|
||||||
sleep(Duration::from_millis(1)).await;
|
sleep(Duration::from_millis(1)).await;
|
||||||
|
|
||||||
Ok(TestHandle {
|
Ok(TestHandle {
|
||||||
_handle: handle,
|
handle,
|
||||||
connection,
|
connection,
|
||||||
_rx_job: rx_job,
|
_rx_job: rx_job,
|
||||||
rx_tdp,
|
rx_tdp,
|
||||||
|
@ -1607,6 +1832,17 @@ mod test {
|
||||||
assert!(test_interface_missing::<PerformanceProfile1>(&test.connection).await);
|
assert!(test_interface_missing::<PerformanceProfile1>(&test.connection).await);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn interface_matches_remote_interface1() {
|
||||||
|
let test = start(all_platform_config(), all_device_config())
|
||||||
|
.await
|
||||||
|
.expect("start");
|
||||||
|
|
||||||
|
assert!(test_interface_matches::<RemoteInterface1>(&test.connection)
|
||||||
|
.await
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn interface_matches_storage1() {
|
async fn interface_matches_storage1() {
|
||||||
let test = start(all_platform_config(), all_device_config())
|
let test = start(all_platform_config(), all_device_config())
|
||||||
|
@ -1750,4 +1986,149 @@ mod test {
|
||||||
.await
|
.await
|
||||||
.unwrap());
|
.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn test_remote_interface_added<I: RemoteInterface + Interface>(
|
||||||
|
test: &TestHandle,
|
||||||
|
new_conn: &Connection,
|
||||||
|
) -> Result<()> {
|
||||||
|
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||||
|
.destination(
|
||||||
|
test.connection
|
||||||
|
.unique_name()
|
||||||
|
.ok_or(anyhow!("no unique name"))?,
|
||||||
|
)?
|
||||||
|
.build()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
ensure!(test_remote_interface_missing::<I>(&proxy, test).await?);
|
||||||
|
|
||||||
|
proxy
|
||||||
|
.register_interface(
|
||||||
|
<I as Interface>::name().as_str(),
|
||||||
|
&ObjectPath::try_from("/foo")?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
ensure!(!test_remote_interface_missing::<I>(&proxy, test).await?);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn test_remote_interface_missing<I: RemoteInterface + Interface>(
|
||||||
|
proxy: &RemoteInterface1Proxy<'_>,
|
||||||
|
test: &TestHandle,
|
||||||
|
) -> Result<bool> {
|
||||||
|
Ok(!proxy
|
||||||
|
.remote_interfaces()
|
||||||
|
.await?
|
||||||
|
.contains(&<I as Interface>::name().to_string())
|
||||||
|
&& test_interface_missing::<<I as RemoteInterface>::Remote>(&test.connection).await)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn remote_battery_charge_limit1() {
|
||||||
|
let test = start(None, None).await.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||||
|
.destination(test.connection.unique_name().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn remote_battery_charge_limit1_dropped() {
|
||||||
|
let test = start(None, None).await.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
drop(new_conn);
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||||
|
.destination(test.connection.unique_name().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn remote_battery_charge_limit1_removed() {
|
||||||
|
let test = start(None, None).await.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||||
|
.destination(test.connection.unique_name().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(proxy
|
||||||
|
.unregister_interface(BatteryChargeLimit1::name().as_str())
|
||||||
|
.await
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn remote_battery_charge_limit1_not_removed() {
|
||||||
|
let test = start(None, None).await.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
test_remote_interface_added::<BatteryChargeLimit1>(&test, &new_conn)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_conn = test.handle.new_connection().await.unwrap();
|
||||||
|
let proxy = RemoteInterface1Proxy::builder(&new_conn)
|
||||||
|
.destination(test.connection.unique_name().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(proxy
|
||||||
|
.unregister_interface(BatteryChargeLimit1::name().as_str())
|
||||||
|
.await
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!test_remote_interface_missing::<BatteryChargeLimit1>(&proxy, &test)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,14 @@ impl TestHandle {
|
||||||
pub async fn dbus_address(&self) -> Option<Address> {
|
pub async fn dbus_address(&self) -> Option<Address> {
|
||||||
(*self.test.dbus_address.lock().await).clone()
|
(*self.test.dbus_address.lock().await).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn new_connection(&self) -> Result<Connection> {
|
||||||
|
Ok(
|
||||||
|
Builder::address(self.dbus_address().await.ok_or(anyhow!("No address"))?)?
|
||||||
|
.build()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestHandle {
|
impl Drop for TestHandle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue