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

Commit beabe251 authored by Yun-Hao Chung's avatar Yun-Hao Chung
Browse files

Floss: Clean up message loop threads when SIGTERM

When terminating btadapterd, we need to gracefully close all of the
message loop threads in libbluetooth otherwise it might crash.

This CL implements the cleanup function for BluetoothMedia as it uses
some threads that doesn't close in btif cleanup.

Bug: 335146967, 304997914, 353900236
Tag: #floss
Test: mmm packages/modules/Bluetooth
Test: run below test mannually while a2dp and hogp is in used
      1. rmmod btusb && modprobe btusb while
      2. hcitool cmd 3f 4e (to trigger hardware error)
Flag: EXEMPT, Floss-only changes
Change-Id: I50ede04357bf8a24efd3d29e96c481961aec42d7
parent 87ca4e29
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -2652,6 +2652,11 @@ impl IBluetoothMedia for BluetoothMediaDBus {
        dbus_generated!()
    }

    #[dbus_method("IsInitialized")]
    fn is_initialized(&self) -> bool {
        dbus_generated!()
    }

    #[dbus_method("Cleanup")]
    fn cleanup(&mut self) -> bool {
        dbus_generated!()
+5 −0
Original line number Diff line number Diff line
@@ -268,6 +268,11 @@ impl IBluetoothMedia for IBluetoothMediaDBus {
        dbus_generated!()
    }

    #[dbus_method("IsInitialized")]
    fn is_initialized(&self) -> bool {
        dbus_generated!()
    }

    #[dbus_method("Cleanup")]
    fn cleanup(&mut self) -> bool {
        dbus_generated!()
+8 −1
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ const ADMIN_SETTINGS_FILE_PATH: &str = "/var/lib/bluetooth/admin_policy.json";
const STACK_TURN_OFF_TIMEOUT_MS: Duration = Duration::from_millis(4000);
// Time bt_stack_manager waits for cleanup
const STACK_CLEANUP_TIMEOUT_MS: Duration = Duration::from_millis(1000);
// Time bt_stack_manager waits for cleanup profiles
const STACK_CLEANUP_PROFILES_TIMEOUT_MS: Duration = Duration::from_millis(100);

const INIT_LOGGING_MAX_RETRY: u8 = 3;

@@ -297,7 +299,12 @@ extern "C" fn handle_sigterm(_signum: i32) {
        log::debug!("SIGTERM cleaning up the stack.");
        let txl = tx.clone();
        tokio::spawn(async move {
            // Send the cleanup message here.
            // Clean up the profiles first as some of them might require main thread to clean up.
            let _ = txl.send(Message::CleanupProfiles).await;
            // Currently there is no good way to know when the profile is cleaned.
            // Simply add a small delay here.
            tokio::time::sleep(STACK_CLEANUP_PROFILES_TIMEOUT_MS).await;
            // Send the cleanup message to clean up the main thread.
            let _ = txl.send(Message::Cleanup).await;
        });

+26 −10
Original line number Diff line number Diff line
@@ -92,6 +92,15 @@ const MEDIA_CLASSIC_AUDIO_PROFILES: &[Profile] =
const MEDIA_LE_AUDIO_PROFILES: &[Profile] =
    &[Profile::LeAudio, Profile::VolumeControl, Profile::CoordinatedSet];

const MEDIA_PROFILE_ENABLE_ORDER: &[Profile] = &[
    Profile::A2dpSource,
    Profile::AvrcpTarget,
    Profile::Hfp,
    Profile::LeAudio,
    Profile::VolumeControl,
    Profile::CoordinatedSet,
];

/// Group ID used to identify unknown/non-existent groups.
pub const LEA_UNKNOWN_GROUP_ID: i32 = -1;

@@ -108,6 +117,9 @@ pub trait IBluetoothMedia {
    /// initializes media (both A2dp and AVRCP) stack
    fn initialize(&mut self) -> bool;

    /// Get if the media stack is initialized.
    fn is_initialized(&self) -> bool;

    /// clean up media stack
    fn cleanup(&mut self) -> bool;

@@ -567,6 +579,14 @@ impl BluetoothMedia {
        }
    }

    pub fn cleanup(&mut self) -> bool {
        for profile in MEDIA_PROFILE_ENABLE_ORDER.iter().rev() {
            self.disable_profile(&profile);
        }
        self.initialized = false;
        true
    }

    fn is_profile_connected(&self, addr: &RawAddress, profile: &Profile) -> bool {
        self.is_any_profile_connected(addr, &[*profile])
    }
@@ -3193,15 +3213,7 @@ impl IBluetoothMedia for BluetoothMedia {

        // TODO(b/284811956) A2DP needs to be enabled before AVRCP otherwise AVRCP gets memset'd.
        // Iterate the delay_enable_profiles hashmap directly when this is fixed.
        let profile_order = vec![
            Profile::A2dpSource,
            Profile::AvrcpTarget,
            Profile::Hfp,
            Profile::LeAudio,
            Profile::VolumeControl,
            Profile::CoordinatedSet,
        ];
        for profile in profile_order {
        for profile in MEDIA_PROFILE_ENABLE_ORDER {
            if self.delay_enable_profiles.contains(&profile) {
                self.enable_profile(&profile);
            }
@@ -3596,8 +3608,12 @@ impl IBluetoothMedia for BluetoothMedia {
        }
    }

    fn is_initialized(&self) -> bool {
        self.initialized
    }

    fn cleanup(&mut self) -> bool {
        true
        self.cleanup()
    }

    // This may not disconnect all media profiles at once, but once the stack
+6 −0
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ pub enum Message {
    AdapterShutdown,
    /// Clean up the adapter by calling btif cleanup.
    Cleanup,
    /// Clean up the media by calling profile cleanup.
    CleanupProfiles,

    // Adapter is enabled and ready.
    AdapterReady,
@@ -250,6 +252,10 @@ impl Stack {
                    bluetooth.lock().unwrap().cleanup();
                }

                Message::CleanupProfiles => {
                    bluetooth_media.lock().unwrap().cleanup();
                }

                Message::AdapterReady => {
                    // Initialize objects that need the adapter to be fully
                    // enabled before running.