Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 517524b3 authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Gerrit Code Review
Browse files

Merge "Floss: Add constraint to service watcher to match service name"

parents bf99d7bc 5a618f68
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -226,7 +226,8 @@ impl PowerdSuspendManager {
            .await;

        // Watch events of btadapterd appearing or disappearing.
        let adapter_watcher = ServiceWatcher::new(self.conn.clone(), String::from(ADAPTER_SERVICE));
        let mut adapter_watcher =
            ServiceWatcher::new(self.conn.clone(), String::from(ADAPTER_SERVICE));
        let tx1 = self.tx.clone();
        let tx2 = self.tx.clone();
        adapter_watcher
@@ -470,7 +471,7 @@ impl PowerdSuspendManager {
    }

    fn on_adapter_found(&mut self, path: dbus::Path<'static>) {
        log::debug!("Found adapter {:?}", path);
        log::debug!("Found adapter suspend {:?}", path);

        let conn = self.conn.clone();
        self.context.lock().unwrap().adapter_suspend_dbus =
@@ -491,7 +492,7 @@ impl PowerdSuspendManager {
    }

    fn on_adapter_removed(&mut self) {
        log::debug!("Adapter removed");
        log::debug!("Adapter suspend removed");
        self.context.lock().unwrap().adapter_suspend_dbus = None;
    }
}
+69 −13
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ use dbus::channel::MatchingReceiver;
use dbus::message::MatchRule;
use dbus::nonblock::stdintf::org_freedesktop_dbus::ObjectManager;
use dbus::nonblock::SyncConnection;
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::time::Duration;

const DBUS_SERVICE: &str = "org.freedesktop.DBus";
@@ -15,18 +15,46 @@ const DBUS_INTERFACES_ADDED: &str = "InterfacesAdded";
const DBUS_PATH: &str = "/org/freedesktop/DBus";
const DBUS_TIMEOUT: Duration = Duration::from_secs(2);

struct ServiceWatcherContext {
    // The service name to watch.
    service_name: String,
    // The owner D-Bus address if exists.
    service_owner: Option<String>,
}

impl ServiceWatcherContext {
    fn new(service_name: String) -> Self {
        Self { service_name, service_owner: None }
    }

    fn set_owner(&mut self, owner: String) {
        log::debug!("setting owner of {} to {}", self.service_name, owner);
        self.service_owner = Some(owner);
    }

    fn unset_owner(&mut self) {
        log::debug!("unsetting owner of {}", self.service_name);
        self.service_owner = None;
    }
}

pub struct ServiceWatcher {
    conn: Arc<SyncConnection>,
    service_name: String,
    context: Arc<Mutex<ServiceWatcherContext>>,
}

impl ServiceWatcher {
    pub fn new(conn: Arc<SyncConnection>, service_name: String) -> Self {
        ServiceWatcher { conn, service_name }
        ServiceWatcher {
            conn,
            service_name: service_name.clone(),
            context: Arc::new(Mutex::new(ServiceWatcherContext::new(service_name))),
        }
    }

    // Returns true if the named D-Bus service is available.
    async fn is_service_available(&self) -> bool {
    // Returns the owner D-Bus address of the named service.
    async fn get_dbus_owner_of_service(&self) -> Option<String> {
        let dbus_proxy =
            dbus::nonblock::Proxy::new(DBUS_SERVICE, DBUS_PATH, DBUS_TIMEOUT, self.conn.clone());

@@ -37,11 +65,11 @@ impl ServiceWatcher {
        match service_owner {
            Err(e) => {
                log::debug!("Getting service owner failed: {}", e);
                false
                None
            }
            Ok((owner,)) => {
                log::debug!("{} service owner = {}", self.service_name, owner);
                true
                log::debug!("Got service owner {} = {}", self.service_name, owner);
                Some(owner)
            }
        }
    }
@@ -69,6 +97,7 @@ impl ServiceWatcher {
        }
    }

    // Monitors the service appearance or disappearance and keeps the owner address updated.
    async fn monitor_name_owner_changed(
        &self,
        on_available: Box<dyn Fn() + Send>,
@@ -77,9 +106,14 @@ impl ServiceWatcher {
        let mr = MatchRule::new_signal(DBUS_INTERFACE, DBUS_NAME_OWNER_CHANGED);
        self.conn.add_match_no_cb(&mr.match_str()).await.unwrap();
        let service_name = self.service_name.clone();
        let context = self.context.clone();
        self.conn.start_receive(
            mr,
            Box::new(move |msg, _conn| {
                // We use [`dbus::nonblock::SyncConnection::set_signal_match_mode`] with
                // `match_all` = true,  so we should always return true from this closure to
                // indicate that we have handled the message and not let other handlers handle this
                // signal.
                if let (Some(name), Some(old_owner), Some(new_owner)) =
                    msg.get3::<String, String, String>()
                {
@@ -90,8 +124,10 @@ impl ServiceWatcher {
                    }

                    if old_owner == "" && new_owner != "" {
                        context.lock().unwrap().set_owner(new_owner.clone());
                        on_available();
                    } else if old_owner != "" && new_owner == "" {
                        context.lock().unwrap().unset_owner();
                        on_unavailable();
                    } else {
                        log::warn!(
@@ -112,8 +148,8 @@ impl ServiceWatcher {
        on_available: Box<dyn Fn() + Send>,
        on_unavailable: Box<dyn Fn() + Send>,
    ) {
        if self.is_service_available().await {
            // If service is already available at the start, just call the hook immediately.
        if let Some(owner) = self.get_dbus_owner_of_service().await {
            self.context.lock().unwrap().set_owner(owner.clone());
            on_available();
        }

@@ -134,12 +170,13 @@ impl ServiceWatcher {
    /// Doesn't take into account the disappearance of the interface itself. At the moment assuming
    /// interfaces do not disappear as long as the service is alive.
    pub async fn start_watch_interface(
        &self,
        &mut self,
        interface: String,
        on_available: Box<dyn Fn(dbus::Path<'static>) + Send>,
        on_unavailable: Box<dyn Fn() + Send>,
    ) {
        if self.is_service_available().await {
        if let Some(owner) = self.get_dbus_owner_of_service().await {
            self.context.lock().unwrap().set_owner(owner.clone());
            if let Some(path) = self.get_path_of_interface(interface.clone()).await {
                on_available(path);
            }
@@ -148,7 +185,7 @@ impl ServiceWatcher {
        // Monitor service disappearing.
        self.monitor_name_owner_changed(
            Box::new(move || {
                // Ignore service appearing because we rely on interface added.
                // Don't trigger on_available() yet because we rely on interface added.
            }),
            Box::new(move || {
                on_unavailable();
@@ -159,15 +196,34 @@ impl ServiceWatcher {
        // Monitor interface appearing.
        let mr = MatchRule::new_signal(DBUS_OBJMGR_INTERFACE, DBUS_INTERFACES_ADDED);
        self.conn.add_match_no_cb(&mr.match_str()).await.unwrap();
        let context = self.context.clone();
        self.conn.start_receive(
            mr,
            Box::new(move |msg, _conn| {
                // We use [`dbus::nonblock::SyncConnection::set_signal_match_mode`] with
                // `match_all` = true,  so we should always return true from this closure to
                // indicate that we have handled the message and not let other handlers handle this
                // signal.
                let (object_path, interfaces) =
                    msg.get2::<dbus::Path, dbus::arg::Dict<String, dbus::arg::PropMap, _>>();
                let interfaces: Vec<String> = interfaces.unwrap().map(|e| e.0).collect();
                if interfaces.contains(&interface) {
                    if let (Some(sender), Some(owner)) =
                        (msg.sender(), context.lock().unwrap().service_owner.as_ref())
                    {
                        // The signal does not come from the service we are watching, ignore.
                        if &sender.to_string() != owner {
                            log::debug!(
                                "Detected interface {} added but sender is {}, expected {}.",
                                interface,
                                sender,
                                owner
                            );
                            return true;
                        }
                        on_available(object_path.unwrap().into_static());
                    }
                }

                true
            }),