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

Commit 965411dc authored by Archie Pusaka's avatar Archie Pusaka
Browse files

floss: hcidoc: fix the disconnection due to host power off

If BT is powered off, it is possible that the controller doesn't
wait until the peer device reply the disconnection request.
Therefore in aosp/2651792 we treat those disconnection request as
a special case. However, sometimes the event will still be replied,
thus we process the disconnection twice.

This CL fixes that by first checking whether the handle was
disconnected due to host power off.

Bug: 293397988
Tag: #floss
Test: Verify report 91229383170 doesn't report disconnection for
      nonexistent connection.
Test: m -j
Change-Id: I1db61463d1d93dd0120951c3a7b514d0167befd6
parent 1ca7e87a
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -107,6 +107,10 @@ struct OddDisconnectionsRule {
    pending_le_feat: HashMap<ConnectionHandle, NaiveDateTime>,
    last_feat_handle: HashMap<PendingRemoteFeature, ConnectionHandle>,

    /// When powering off, the controller might or might not reply disconnection request. Therefore
    /// make this a special case.
    pending_disconnect_due_to_host_power_off: HashSet<ConnectionHandle>,

    /// Pre-defined signals discovered in the logs.
    signals: Vec<Signal>,

@@ -132,6 +136,7 @@ impl OddDisconnectionsRule {
            pending_extended_feat: HashMap::new(),
            pending_le_feat: HashMap::new(),
            last_feat_handle: HashMap::new(),
            pending_disconnect_due_to_host_power_off: HashSet::new(),
            signals: vec![],
            reportable: vec![],
        }
@@ -217,12 +222,12 @@ impl OddDisconnectionsRule {
        &mut self,
        reason: DisconnectReason,
        handle: ConnectionHandle,
        _packet: &Packet,
        packet: &Packet,
    ) {
        // If reason is power off, the host might not wait for connection complete event
        if reason == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff {
            self.active_handles.remove(&handle);
            self.nocp_by_handle.remove(&handle);
            self.process_disconn_complete_ev(handle, packet);
            self.pending_disconnect_due_to_host_power_off.insert(handle);
        }
    }

@@ -361,6 +366,11 @@ impl OddDisconnectionsRule {
    }

    fn process_disconn_complete_ev(&mut self, handle: ConnectionHandle, packet: &Packet) {
        // If previously host send disconnect with power off reason, disconnection has been handled.
        if self.pending_disconnect_due_to_host_power_off.remove(&handle) {
            return;
        }

        self.active_handles.remove(&handle);

        // Check if this is a NOCP type disconnection and flag it.
@@ -588,6 +598,7 @@ impl OddDisconnectionsRule {
        self.pending_extended_feat.clear();
        self.pending_le_feat.clear();
        self.last_feat_handle.clear();
        self.pending_disconnect_due_to_host_power_off.clear();
    }
}

+16 −2
Original line number Diff line number Diff line
@@ -326,8 +326,11 @@ struct InformationalRule {
    devices: HashMap<Address, DeviceInformation>,
    handles: HashMap<ConnectionHandle, Address>,
    sco_handles: HashMap<ConnectionHandle, ConnectionHandle>,
    // unknownConnections store connections which is initiated before btsnoop starts.
    /// unknownConnections store connections which is initiated before btsnoop starts.
    unknown_connections: HashMap<ConnectionHandle, AclInformation>,
    /// When powering off, the controller might or might not reply disconnection request. Therefore
    /// make this a special case.
    pending_disconnect_due_to_host_power_off: HashSet<ConnectionHandle>,
}

impl InformationalRule {
@@ -337,6 +340,7 @@ impl InformationalRule {
            handles: HashMap::new(),
            sco_handles: HashMap::new(),
            unknown_connections: HashMap::new(),
            pending_disconnect_due_to_host_power_off: HashSet::new(),
        }
    }

@@ -454,6 +458,7 @@ impl InformationalRule {
            self.report_connection_end(handle, ts);
        }
        self.sco_handles.clear();
        self.pending_disconnect_due_to_host_power_off.clear();
    }

    fn _report_profile_start(
@@ -537,8 +542,15 @@ impl Rule for InformationalRule {
                }

                EventChild::DisconnectionComplete(ev) => {
                    // If disconnected because host is powering off, the event has been processed.
                    // We can't just query the reason here because it's different across vendors.
                    if !self
                        .pending_disconnect_due_to_host_power_off
                        .remove(&ev.get_connection_handle())
                    {
                        self.report_connection_end(ev.get_connection_handle(), packet.ts);
                    }
                }

                EventChild::ExtendedInquiryResult(ev) => {
                    for data in ev.get_extended_inquiry_response() {
@@ -638,6 +650,8 @@ impl Rule for InformationalRule {
                        if cmd.get_reason()
                            == DisconnectReason::RemoteDeviceTerminatedConnectionPowerOff
                        {
                            self.pending_disconnect_due_to_host_power_off
                                .insert(cmd.get_connection_handle());
                            self.report_connection_end(cmd.get_connection_handle(), packet.ts);
                        }
                    }