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

Commit 2c0570b5 authored by Zhengping Jiang's avatar Zhengping Jiang
Browse files

floss: start resume if suspend is aborted

If the suspend is aborted in the powerd, the SuspendImminent signal is
cancelled after receiving SuspendDone. Bluetooth will start the resume
flow after the suspend is ready.

Put LE Rand to the end of the suspend/resume flow, so the callback can
clean the states properly.

Tag: #floss
Bug: 324424415
Test: shift+search+L
Test: mma -j32
Flag: EXEMPT, floss change for ChromeOS only.

Change-Id: Ibdb087d2d2e5aa9938c2debd8f74f4208b6f41b6
parent 41af6118
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -125,6 +125,11 @@ impl ISuspendCallback for SuspendCallback {
        {
            let context = self.context.lock().unwrap();

            if context.powerd_session.is_none() {
                log::warn!("No powerd session!");
                return;
            }

            if let (Some(pending_suspend_imminent), Some(powerd_session)) =
                (&context.pending_suspend_imminent, &context.powerd_session)
            {
@@ -133,8 +138,21 @@ impl ISuspendCallback for SuspendCallback {
                    powerd_session.delay_id,
                    pending_suspend_imminent.get_suspend_id(),
                );
            } else if let (Some(adapter_suspend_dbus), None) =
                (&context.adapter_suspend_dbus, &context.pending_suspend_imminent)
            {
                log::info!("Suspend was aborted (imminent signal missing), so calling resume");
                let mut suspend_dbus_rpc = adapter_suspend_dbus.rpc.clone();
                tokio::spawn(async move {
                    let result = suspend_dbus_rpc.resume().await;
                    log::debug!("Adapter resume call, success = {}", result.unwrap_or(false));
                });
            } else {
                log::warn!("Suspend ready but no SuspendImminent signal or powerd session");
                log::warn!(
                    "Suspend ready but powerd session valid={}, adapter available={}.",
                    context.powerd_session.is_some(),
                    context.adapter_suspend_dbus.is_some()
                );
            }
        }
    }
@@ -498,11 +516,13 @@ impl PowerdSuspendManager {
    fn on_suspend_done(&mut self, suspend_done: SuspendDone) {
        // powerd is telling us that suspend is done (system has resumed), so we tell btadapterd
        // to resume too.
        // powerd also sends the suspend done signal when the suspend is aborted. The suspend
        // imminent signal is cancelled here, so the cleanup is done after the suspend is ready.

        log::debug!("SuspendDone received: {:?}", suspend_done);

        if self.context.lock().unwrap().pending_suspend_imminent.is_none() {
            log::warn!("Receveid SuspendDone signal when there is no pending SuspendImminent");
            log::warn!("Received SuspendDone signal when there is no pending SuspendImminent");
        }

        self.context.lock().unwrap().pending_suspend_imminent = None;
+23 −5
Original line number Diff line number Diff line
@@ -231,6 +231,8 @@ impl ISuspend for Suspend {
    }

    fn suspend(&mut self, suspend_type: SuspendType, suspend_id: i32) {
        // Set suspend state as true, prevent an early resume.
        self.suspend_state.lock().unwrap().suspend_expected = true;
        // Set suspend event mask
        self.intf.lock().unwrap().set_default_event_mask_except(MASKED_EVENTS_FOR_SUSPEND, 0u64);

@@ -269,9 +271,7 @@ impl ISuspend for Suspend {
            _ => {}
        }
        self.suspend_state.lock().unwrap().le_rand_expected = true;
        self.suspend_state.lock().unwrap().suspend_expected = true;
        self.suspend_state.lock().unwrap().suspend_id = Some(suspend_id);
        self.bt.lock().unwrap().le_rand();

        if let Some(join_handle) = &self.suspend_timeout_joinhandle {
            join_handle.abort();
@@ -283,16 +283,25 @@ impl ISuspend for Suspend {
        self.suspend_timeout_joinhandle = Some(tokio::spawn(async move {
            tokio::time::sleep(tokio::time::Duration::from_millis(2000)).await;
            log::error!("Suspend did not complete in 2 seconds, continuing anyway.");

            suspend_state.lock().unwrap().le_rand_expected = false;
            suspend_state.lock().unwrap().suspend_expected = false;
            tokio::spawn(async move {
                let _result = tx.send(Message::SuspendReady(suspend_id)).await;
            });
        }));

        // Call LE Rand at the end of suspend. The callback of LE Rand will reset the
        // suspend state, cancel the suspend timeout and send suspend ready signal.
        self.bt.lock().unwrap().le_rand();
    }

    fn resume(&mut self) -> bool {
        // Suspend is not ready (e.g. aborted early), delay cleanup after SuspendReady.
        if self.suspend_state.lock().unwrap().suspend_expected == true {
            log::error!("Suspend is expected but not ready, abort resume.");
            return false;
        }

        // Suspend ID state 0: NoRecord, 1: Recorded
        let suspend_id_state = match self.suspend_state.lock().unwrap().suspend_id {
            None => {
@@ -362,7 +371,6 @@ impl ISuspend for Suspend {

        self.suspend_state.lock().unwrap().le_rand_expected = true;
        self.suspend_state.lock().unwrap().resume_expected = true;
        self.bt.lock().unwrap().le_rand();

        let tx = self.tx.clone();
        let suspend_state = self.suspend_state.clone();
@@ -378,6 +386,10 @@ impl ISuspend for Suspend {
            });
        }));

        // Call LE Rand at the end of resume. The callback of LE Rand will reset the
        // resume state and send resume ready signal.
        self.bt.lock().unwrap().le_rand();

        true
    }
}
@@ -400,13 +412,19 @@ impl BtifBluetoothCallbacks for Suspend {
        let suspend_id = self.suspend_state.lock().unwrap().suspend_id.unwrap();

        if self.suspend_state.lock().unwrap().suspend_expected {
            self.suspend_state.lock().unwrap().suspend_expected = false;
            let suspend_state = self.suspend_state.clone();
            let tx = self.tx.clone();
            tokio::spawn(async move {
                // TODO(b/286268874) Add a short delay because HCI commands are not
                // synchronized. LE Rand is the last command, so wait for other
                // commands to finish. Remove after synchronization is fixed.
                tokio::time::sleep(tokio::time::Duration::from_millis(
                    LE_RAND_CB_SUSPEND_READY_DELAY_MS,
                ))
                .await;
                // TODO(b/286268874) Reset suspend state after the delay. Prevent
                // resume until the suspend ready signal is sent.
                suspend_state.lock().unwrap().suspend_expected = false;
                let _result = tx.send(Message::SuspendReady(suspend_id)).await;
            });
        }