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

Commit f43df148 authored by Abhishek Pandit-Subedi's avatar Abhishek Pandit-Subedi Committed by Abhishek Pandit-Subedi
Browse files

floss: Client checks if manager is valid

Add a check to make sure the manager is valid before using it in
btclient. This change doesn't exit right away if it's invalid and
instead allows the next command to fail (RegisterCallback) which gives
the reason for the failure.

Bug: 202023404
Tag: #floss
Test: Try running btclient with no btmanagerd running
Change-Id: If772cc729afc3fad3e0abb8aa2351157521d0f1d
parent e96e8c77
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -112,28 +112,34 @@ impl ClientDBusProxy {
        )
    }

    fn method<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
    /// Calls a method and returns the dbus result.
    fn method_withresult<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
        &self,
        member: &str,
        args: A,
    ) -> T {
    ) -> Result<(T,), dbus::Error> {
        let proxy = self.create_proxy();
        // We know that all APIs return immediately, so we can block on it for simplicity.
        let (ret,): (T,) = futures::executor::block_on(async {
        return futures::executor::block_on(async {
            proxy.method_call(self.interface.clone(), member, args).await
        })
        .unwrap();
        });
    }

    fn method<A: AppendAll, T: 'static + dbus::arg::Arg + for<'z> dbus::arg::Get<'z>>(
        &self,
        member: &str,
        args: A,
    ) -> T {
        let (ret,): (T,) = self.method_withresult(member, args).unwrap();
        return ret;
    }

    fn method_noreturn<A: AppendAll>(&self, member: &str, args: A) {
        let proxy = self.create_proxy();
        // We know that all APIs return immediately, so we can block on it for simplicity.
        let _: () = futures::executor::block_on(async {
            proxy.method_call(self.interface.clone(), member, args).await
        })
        .unwrap();
        // The real type should be Result<((),), _> since there is no return value. However, to
        // meet trait constraints, we just use bool and never unwrap the result. This calls the
        // method, waits for the response but doesn't actually attempt to parse the result (on
        // unwrap).
        let _: Result<(bool,), _> = self.method_withresult(member, args);
    }
}

@@ -410,6 +416,11 @@ impl BluetoothManagerDBus {
            },
        }
    }

    pub(crate) fn is_valid(&self) -> bool {
        let result: Result<(bool,), _> = self.client_proxy.method_withresult("GetFlossEnabled", ());
        return result.is_ok();
    }
}

// TODO: These are boilerplate codes, consider creating a macro to generate.
+11 −2
Original line number Diff line number Diff line
@@ -80,8 +80,8 @@ impl ClientContext {
        dbus_crossroads: Arc<Mutex<Crossroads>>,
        tx: mpsc::Sender<ForegroundActions>,
    ) -> ClientContext {
        // Manager interface is always available but adapter interface requires
        // that the specific adapter is enabled.
        // Manager interface is almost always available but adapter interface
        // requires that the specific adapter is enabled.
        let manager_dbus =
            BluetoothManagerDBus::new(dbus_connection.clone(), dbus_crossroads.clone());

@@ -214,6 +214,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
        // Create the context needed for handling commands
        let context = Arc::new(Mutex::new(ClientContext::new(conn, cr, tx.clone())));

        // Check if manager interface is valid. We only print some help text before failing on the
        // first actual access to the interface (so we can also capture the actual reason the
        // interface isn't valid).
        if !context.lock().unwrap().manager_dbus.is_valid() {
            println!("Bluetooth manager doesn't seem to be working correctly.");
            println!("Check if service is running.");
            println!("...");
        }

        // TODO: Registering the callback should be done when btmanagerd is ready (detect with
        // ObjectManager).
        context.lock().unwrap().manager_dbus.register_callback(Box::new(BtManagerCallback::new(