Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HAP: wait for pairing event #551

Merged
merged 1 commit into from
Oct 10, 2024
Merged

HAP: wait for pairing event #551

merged 1 commit into from
Oct 10, 2024

Conversation

wescande
Copy link
Contributor

HAP is supposed to work only when device are bonded.

By listening to the on_pairing event of the connection, we can start add the remote device to the preset_changed_operations_history_per_device only after the bonding (and thus the public address) has been done.

This missing logic was found thanks to https://r.android.com/3236429, an avatar test that try to delete a preset and then wait for the notification / indication to be sent to the device

await self._preset_changed_operation(connection)
# Update the active preset index if needed
await self.notify_active_preset_for_connection(connection)
@connection.on('pairing') # type: ignore
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue here is that this only remembers paired connections when the pairing happens while the service is running. But what about connections from devices that were previously paired and bonded?

Copy link
Contributor Author

@wescande wescande Sep 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that setting up HAS is done before we connect to a remote device.

If an already paired device reconnect, it should go in this if:

            if connection.peer_resolvable_address:
                self.on_incoming_paired_connection(connection)

directly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A problem here is that peer_resolvable_address may not be set if identity information is not exchanged (though Android almost always does that). I didn't find a clear identity requirement in HAP (besides IAC https://www.bluetooth.com/specifications/specs/hap-1-0/ ), so I am afraid checking RPA is not very precise here.

Since what HAP requires is an LTK, maybe we can make on_connection an async function (using utils.AsyncRunner) and check whether LTK is available via device.get_long_term_key(...)?

Copy link
Collaborator

@zxzxwu zxzxwu Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example:

    def __init__(
        self, device: Device, features: HearingAidFeatures, presets: List[PresetRecord]
    ) -> None:
        ...
        device.on('connection', self.on_connection)

    @AsyncRunner.run_in_task()
    async def on_connection(self, connection: Connection) -> None:
        def on_disconnection(reason: int) -> None:
            del reason  # unused
            # BTW, reference of connection might change here, so we had better freeze it with functool.partial
            self.currently_connected_clients.remove(connection)

        connection.on('disconnection', on_disconnection)

        # TODO Should we filter on device bonded && device is HAP ?
        self.currently_connected_clients.add(connection)
        if (
            connection.peer_address
            not in self.preset_changed_operations_history_per_device
        ):
            self.preset_changed_operations_history_per_device[
                connection.peer_address
            ] = []
            return

        # Send all the PresetChangedOperation that occur when not connected
        await self._preset_changed_operation(connection)
        # Update the active preset index if needed
        await self.notify_active_preset_for_connection(connection)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what about connections from devices that were previously paired and bonded?

In what scenario do we have previously paired and bonded devices without HAS knowing it ? I believe HAS is present since the device is "alive".

Could we open a bug to track this specific behavior instead and implement it later ? We would need this PR to land to merge some HAP Avatar test within Android.

@zxzxwu
Copy link
Collaborator

zxzxwu commented Sep 11, 2024

My opinion is that Bumble is not designed for persistent usage, so it's better to do this kind of operations at the caller side, which has more (well-controlled) context of persistent states.

@wescande
Copy link
Contributor Author

@zxzxwu, the service need to notify every currently connected devices.
So in parallel of the "persistent usage", has need to know about devices only when paired. Which is the goal of this CL.

The only persistent code in has is to update the device after re connection. I haven't implemented any persistent storage that would works between multiples bumble restart. They are only lasting as long as the current bumble is running.

@SilverBzH
Copy link
Collaborator

Is it possible to merge this PR ?

@wescande
Copy link
Contributor Author

wescande commented Oct 1, 2024

I believe that the PR is ready and just need approval.
The HAP will not work properly without this change.

I have a bumble related test that exercise the logic added here and require it in order to pass:
https://android-review.git.corp.google.com/c/platform/packages/modules/Bluetooth/+/3236429

@zxzxwu
Copy link
Collaborator

zxzxwu commented Oct 4, 2024 via email

@barbibulle
Copy link
Collaborator

I think it's Ok to merge the PR as is, even if the detection of previously bonded devices across a restart of the device/app isn't going to work. Support for persistence that way can be added later in a separate PR.
In general, support for bond persistence with Bumble is supported by the JsonKeyStore implementation (for a future enhancement, I'll think about adding convenience methods to ask if a device is bonded or not, for example). A custom device app/test may implement a different notion of persistence, either with a custom KeyStore implementation, or a limited-scope single lifetime persistence as is done here.
@zxzxwu do you think it's an issue to merge this code as it is now and unblock the work that needs it?

@zxzxwu
Copy link
Collaborator

zxzxwu commented Oct 9, 2024

I don't have much opinion on this PR besides #551 (comment). Checking pairing record with identity address is not a good approach.

@barbibulle
Copy link
Collaborator

I don't have much opinion on this PR besides #551 (comment). Checking pairing record with identity address is not a good approach.

I agree that checking for peer_resolvable_address to infer a previous bond isn't 100% reliable (but should work in most cases, because it would be uncommon for a device to not share its identity during bonding).
I'll mark this PR as approved for now, and try to propose a more reliable, supported API for checking a device's bonded state, via the keystore, which we can then use later.

@SilverBzH SilverBzH merged commit 23f46b3 into google:main Oct 10, 2024
57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants