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

Commit 1ee44bcf authored by Jeremy Wu's avatar Jeremy Wu
Browse files

Floss: validate connection state in bluetooth_media

It is discovered that in some cases a profile-disconnection request may
be received when it was not connected. This will serve as a false alarm
that would cause the device to be removed from the audio stack.

In this CL, we validate the connection state so that if the connection
state already matches what was requested, we will just ignore it.

Bug: 248325887
Tag: #floss
Test: Build and verify
Change-Id: I5a784c81fc8d5dc01057f921a1e998954c570a8a
parent 6566877c
Loading
Loading
Loading
Loading
+63 −67
Original line number Diff line number Diff line
@@ -193,6 +193,44 @@ impl BluetoothMedia {
        }
    }

    fn is_profile_connected(&self, addr: RawAddress, profile: uuid::Profile) -> bool {
        if let Some(connected_profiles) = self.connected_profiles.get(&addr) {
            return connected_profiles.contains(&profile);
        }
        return false;
    }

    fn add_connected_profile(&mut self, addr: RawAddress, profile: uuid::Profile) {
        if self.is_profile_connected(addr, profile) {
            warn!("[{}]: profile is already connected", addr.to_string());
            return;
        }

        self.connected_profiles.entry(addr).or_insert_with(HashSet::new).insert(profile);

        self.notify_media_capability_updated(addr);
    }

    fn rm_connected_profile(
        &mut self,
        addr: RawAddress,
        profile: uuid::Profile,
        is_profile_critical: bool,
    ) {
        if !self.is_profile_connected(addr, profile) {
            warn!("[{}]: profile is already disconnected", addr.to_string());
            return;
        }

        self.connected_profiles.entry(addr).or_insert_with(HashSet::new).remove(&profile);

        if is_profile_critical {
            self.notify_critical_profile_disconnected(addr);
        }

        self.notify_media_capability_updated(addr);
    }

    pub fn set_adapter(&mut self, adapter: Arc<Mutex<Box<Bluetooth>>>) {
        self.adapter = Some(adapter);
    }
@@ -215,32 +253,15 @@ impl BluetoothMedia {
                    BtavConnectionState::Connected => {
                        info!("[{}]: a2dp connected.", addr.to_string());
                        self.a2dp_states.insert(addr, state);

                        self.connected_profiles
                            .entry(addr)
                            .or_insert_with(HashSet::new)
                            .insert(uuid::Profile::A2dpSink);

                        self.notify_media_capability_updated(addr);
                        self.add_connected_profile(addr, uuid::Profile::A2dpSink);
                    }
                    BtavConnectionState::Disconnected => match self.a2dp_states.remove(&addr) {
                        Some(_) => {
                    BtavConnectionState::Disconnected => {
                        info!("[{}]: a2dp disconnected.", addr.to_string());
                        self.a2dp_states.remove(&addr);
                        self.a2dp_caps.remove(&addr);
                        self.a2dp_audio_state.remove(&addr);

                            self.connected_profiles
                                .entry(addr)
                                .or_insert_with(HashSet::new)
                                .remove(&uuid::Profile::A2dpSink);

                            self.notify_critical_profile_disconnected(addr);
                            self.notify_media_capability_updated(addr);
                        }
                        None => {
                            warn!("[{}]: Unknown address a2dp disconnected.", addr.to_string());
                        self.rm_connected_profile(addr, uuid::Profile::A2dpSink, true);
                    }
                    },
                    _ => {
                        self.a2dp_states.insert(addr, state);
                    }
@@ -280,19 +301,14 @@ impl BluetoothMedia {

                self.absolute_volume = supported;

                self.connected_profiles
                    .entry(addr)
                    .or_insert_with(HashSet::new)
                    .insert(uuid::Profile::AvrcpController);

                self.notify_media_capability_updated(addr);

                metrics::profile_connection_state_changed(
                    addr,
                    Profile::AvrcpController as u32,
                    BtStatus::Success,
                    BtavConnectionState::Connected as u32,
                );

                self.add_connected_profile(addr, uuid::Profile::AvrcpController);
            }
            AvrcpCallbacks::AvrcpDeviceDisconnected(addr) => {
                info!("[{}]: avrcp disconnected.", addr.to_string());
@@ -302,18 +318,12 @@ impl BluetoothMedia {
                // TODO: better support for multi-device
                self.absolute_volume = false;

                self.connected_profiles
                    .entry(addr)
                    .or_insert_with(HashSet::new)
                    .remove(&uuid::Profile::AvrcpController);

                // This may be considered a critical profile in the extreme case
                // where only AVRCP was connected.
                if self.connected_profiles.is_empty() {
                    self.notify_critical_profile_disconnected(addr);
                }

                self.notify_media_capability_updated(addr);
                let is_profile_critical = match self.connected_profiles.get(&addr) {
                    Some(profiles) => *profiles == HashSet::from([uuid::Profile::AvrcpController]),
                    None => false,
                };

                metrics::profile_connection_state_changed(
                    addr,
@@ -321,6 +331,12 @@ impl BluetoothMedia {
                    BtStatus::Success,
                    BtavConnectionState::Disconnected as u32,
                );

                self.rm_connected_profile(
                    addr,
                    uuid::Profile::AvrcpController,
                    is_profile_critical,
                );
            }
            AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
                self.callbacks.lock().unwrap().for_all_callbacks(|callback| {
@@ -371,34 +387,14 @@ impl BluetoothMedia {
                        if !self.hfp_cap.contains_key(&addr) {
                            self.hfp_cap.insert(addr, HfpCodecCapability::CVSD);
                        }

                        self.connected_profiles
                            .entry(addr)
                            .or_insert_with(HashSet::new)
                            .insert(uuid::Profile::Hfp);

                        self.notify_media_capability_updated(addr);
                        self.add_connected_profile(addr, uuid::Profile::Hfp);
                    }
                    BthfConnectionState::Disconnected => {
                        info!("[{}]: hfp disconnected.", addr.to_string());
                        match self.hfp_states.remove(&addr) {
                            Some(_) => {
                        self.hfp_states.remove(&addr);
                        self.hfp_cap.remove(&addr);
                        self.hfp_audio_state.remove(&addr);

                                self.connected_profiles
                                    .entry(addr)
                                    .or_insert_with(HashSet::new)
                                    .remove(&uuid::Profile::Hfp);

                                self.notify_critical_profile_disconnected(addr);
                                self.notify_media_capability_updated(addr);
                            }
                            None => {
                                warn!("[{}] Unknown address hfp disconnected.", addr.to_string())
                            }
                        }
                        return;
                        self.rm_connected_profile(addr, uuid::Profile::Hfp, true);
                    }
                    BthfConnectionState::Connecting => {
                        info!("[{}]: hfp connecting.", addr.to_string());